iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 3
0
自我挑戰組

來讀設計模式:Junior developer 跟大家一起練功系列 第 8

DAY8: 用不同觀點看物件與封裝

今天我們將再次審視物件導向設計,並且帶入本書作者的新觀點。作者自己提到,接下來提到的看法可能並不會有太多的原創性,但是

稱之為新觀點,是指對於大多數開發人員而言它都可能是看待物件導向的新方式。

本章確實給了我一個新的角度去看物件導向,所以就來看看作者怎麼說吧!

物件

首先我們先看看物件。

傳統觀點

傳統對物件的看法就是具有方法的資料;具有描述問題領域中狀態的資料以及增加其處理資料的方法。

新觀點

我們應該從概念視角出發(回顧三種軟體開發的視角),也就是物件是具有責任的一個實體(責任將決定行為);有時也會把物件視為具有特定行為的實體

這樣定義的好處:使我們專注物件的意圖與行為,而無需太早關心細節以及如何實作

同時,我們只關注物件的公開介面。我們無需知道物件內部如何運作、如何處理資訊,以及需要什麼樣其他的資訊。我們可以將責任全權委任給它。

將焦點放在動機,而非實作

封裝

接著,我們來看封裝。

傳統觀點

傳統上,我們會認為封裝就是將「資料隱藏」。

新觀點

但實際上,我們可以把封裝視為任何形式的隱藏。除了隱藏資料外,也可以是隱藏:

  • 實作細節
  • 衍生類別
  • 設計細節
  • 實體化規則

實作細節的部分,就如同 Day7 提到 Shape 的例子。我們把實作的細節「封裝」了起來。

該例還有許多種上述的封裝類型,值得大家再回頭看看,我們這裡把他們點出來。

  • 資料的封裝PointLineSquare 以及 Circle 中的資料對其他所有物件是隱藏的
  • 方法的封裝:例如 Circle 中的 display method
  • 其他物件的封裝:除了 Circle,圖中其他物件對 MyCircle 一無所知
  • 類型的封裝:客戶並不知道自己接觸到的是哪一種 Shape

類別的再利用

早期物件導向的推廣者曾提倡過「類別的再利用」。這是什麼意思呢?

它指的是先建立基礎類別 (Base Class),然後再從這些基礎類別衍生出新類別。基礎類別常被稱為一般化類別、衍生的子類別被稱為特殊化類別

舉例來說,今天我需要一個五角形,並對他做一些操作(各式各樣的繪製、塗色、消除等等),我們就如是定義了一個類別 Pentagon

而後來我們遇見了一個邊線較為特別的五角形,需要有一種新的繪製邊線的方式,那麼根據上面的描述,我們的做法會是從 Pentagon 衍生出一個類別 PentagonSpecialBorder,其中繪製邊線的方法會有所不同。從 UML 圖,我們會如此表示。

類別的再利用可能存在問題

如此的操作很直覺,但或許會產生一些問題:

此方式的問題 說明
可能導致弱內聚 如果另外存在許多不同邊線類型,那麼 Pentagon 就必須另外關心所有不同的變現繪製。這樣使類別處理更多問題
減少再利用的可能性 不同繪製邊線的 methods 無法再利用,其他地方無法存取
無法根據變化良好伸縮 為了因應所有選擇,需要不斷地特殊化 Pentagon 類別,不幸地話(很常發˙生)有可能發生程式碼重複的問題

好的繼承方式,可能會是依照相同的行為分類。

發現變化並將其封裝

GoF 再次現身開示:

考慮你的設計中哪些地方可能變化。這種方式與關注會導致重新設計的原因相反。它不是考慮什麼會迫使你的設計改變,而是考慮你怎樣才能夠不重新設計的狀況下進行改變。這裡的關鍵在於封裝發生變化的概念,這是許多設計模式的主題。

簡言之,作者的說法是:

發現變化並將其封裝。

將封裝看成透過抽象類別或者介面隱藏類別(類型封裝),GoF 說的話或許就不會那麼難以理解。

舉例子:動物世界

舉個例子,今天我們需要對動物的不同特徵作建模。需求如下:

  • 每種動物都有數量不同的
  • 動物物件必須要能記住並且獲取這項資訊
  • 每種動物的移動方式都不相同

對於腿的部分來說,典型的做法會是設一個資料元素存放腿的數量,也許也需要相關的 method 來取出這項資料元素(例如 getLeg)。複雜的部分在於處理行為上(移動方式)。

我們假設有兩種可能的移動方式:飛行和行走。兩種不同的方法有兩種不同的實作的程式碼。既然存在兩種不同 methods,我們可能有以下兩種解決方案:

  • 用一項資料元素去標注該物件有哪種移動方式
  • 衍伸自 Animal 類別,一個表示能行走、一個能飛。

但後來會發現兩種方式都不太理想。因為在今天的情境下,我們只關注「移動方式」,如果我們再將「食性(肉食性、草食性、雜食性)行為」放進去考量的話,那麼各種排列組合⋯⋯ Jesus Christ, it'll never end.

當一個類別處理愈來愈多不同的變化,程式碼的內聚性會因此降低。

觀察不同的行為,將其封裝(類型的封裝)

那麼我們可以換個方式思考,將 Animal 類別包含具有一個合適移動行為的物件,如圖

這個解決方案會是不久之後會提到的設計模式之一,大家可以先自行參透一下。程式碼實作的部分,也會在往後的介紹到的時候,做更詳細的補充。

接下來

明天我會繼續把 Chapter 8 的部分 cover 完,會簡單地提到共變性與可變性分析,以及一點點的敏捷開發。 See you guys tomorrow!


上一篇
DAY7: Adapter 模式
下一篇
DAY9: 共通性與可變性分析;敏捷程式設計
系列文
來讀設計模式:Junior developer 跟大家一起練功22

尚未有邦友留言

立即登入留言