2014年4月10日 星期四

設計模式 (十) 開拓視野 part1

關於物件導向設計有三個基本概念,物件,封裝和抽象類別,設計人員對這些概念的看法是很重要的,傳統的看法有很大的侷限性

傳統的概念

  1. 將物件視為資料和方法的簡單集合
  2. 封裝視為資料隱藏
  3. 繼承 = 特殊化再利用
新的看法

  1. 將物件視為具有責任的東西
  2. 封裝視為隱藏一切的一種能力
  3. 繼承 = 物件分類的一種方法
  4. 共通性與可變性分析
  5. 概念視角,規約視角,實作視角抽象類別與衍生類別的關係
  6. 設計模式與敏捷程式設計方法的差別(冗餘性,可讀性,測試性)

物件

以傳統的方式來看,物件只不過是個資料處理的方法,然而新的看法則是物件是一個具有責任的實體,這兩個差別在於,將物件視為一個責任的實體會讓我們更專注於物件的意圖(責任),而不是如何實作他,我們可以利用這個概念
  1. 做出初步的設計,這個物件的責任為何,(interface abstract)各種抽象的概念
  2. 當我們將一切的職責分配完成再來關心實作部分
舉個例子來說

有個需求希望在畫面上顯示/移除形狀,依照這個需求我們可以想像出一個物件需要負責這些事情
  1. 選擇一種形狀
  2. 顯示
  3. 移除
  4. 取得位置
再進一步仔細想想,是否有發現,所有的形狀物件都一定擁有2,3,4三個必要功能(責任)
所以最後的UML圖會長像是下面的樣子
在此時我們尚未關注細節,我並不曉得方形該怎麼顯示,更不知道三角形該如何取得各點的位置,我不需要瞭解到細節,事實上,這種概念將物件的實作與使用他的物件解耦了。


封裝

傳統的看法為資料的隱藏,然後這種看法侷限性太大了,新的看法則是將封裝視為任何型式的隱藏
  1. 實作細節
  2. 衍生類別
  3. 設計細節
  4. 實體化設計

讓我們看看上面的UML圖,這是一個adapter pattern的UML圖

Shape shape = new Rectangle(); 
  • 這個動作為類的封裝

shape.Display();  
  • 實作的封裝

利用adapter pattern 將 third-party Circle封裝進 Circle  
  • 其他物件的封裝
Rectangle / Triangle/Circle ,詳細的資料只存在自己的class內部,例如一些flag ,各自的location....etc
  • 資料的封裝

用這種更寬廣方式來看待封裝,優點就是能夠帶來一種更容易分解程式的方法,而封裝層就成為了設計需要遵循的介面,透過封裝Shape的衍生類別,當我有新的形狀要加入時只需要新增一個class就好了,並不會對其他的程式造成影響。

早期的提倡者,曾將類別得再利用作為巨大的優勢,通常都是建立一個基礎類別之後,然後再從基礎類別衍生出新的特殊化的類別,如下圖


可以想成是普通的圓形以及以虛線畫成的特殊圓形,
利用繼承的好處是我可以快速的利用Circle已經實作的程式碼,但是...........
壞處呢?

  • 繼承造成了弱內聚,我再修改Circle的程式碼時,我還必須關注SpecialCircle是否會出現SideEffect。
  • 假設我今天希望畫一個虛線版本的三角形呢? 畫虛線的程式碼是否無法再利用,我必須重新建立一個新的物件叫做SpecialTriangle,然後裡頭再重新實作虛線的功能,這種作法減少了程式碼的再利用性
  • 同上面描述的,這也減少了物件的延展性,假設今天有更多更多的類別出現,粗線圓形,紅色圓形,漸層圓形,你會發現程式越來越難改,if else判斷越加越多,bug越來越多?!
而另一種方式則是依相同行為分類,使用聚合,關於這部分會在part2的時候做更多的說明~

沒有留言:

張貼留言