2014年4月13日 星期日

設計模式 (十一) 開拓視野 part2

開拓視野 part1 提出了物件,封裝,繼承的一些不同看法,在part2會針對聚合,共通性和可變性分析與抽象類別,以及敏捷程式設計的品質做相關的介紹。

在part1我們可以瞭解到特殊化繼承帶來的便利性,以及之後所造成的麻煩,為了避免這個問題,我們可以使用聚合的方式將需要的功能帶入,卻又可以保持內聚性以及封裝性,

舉個例子
現在有個需求

  • 每種動物都有數量不同的腿
  • 動物物件必須能夠記住並獲取這一資訊
  • 每種動物的移動方式都不同
  • 對於指定的地形類型,動物物件必須能夠計算出往返的時間
接著該怎麼實作呢?
我們發現每種動物的移動方式是不同的,有些動物是會飛,有些動物會跑,有些動物會游泳,我們總不能為了每種動物都使用一個method吧,但是我們發現他們的都有移動的行為,我們發現了變化(移動方式),同時我們也發現了相同的概念(移動的行為),所以我們可以將變化的部分封裝起來,在Design pattern中有提到

考慮設計中哪些地方可能有變化,如何在不重新設計的情況下增加需求因應變化,關鍵在於封裝變化的概念。

經過封裝變化之後我們的uml 會如下所示

這麼做的好處在於,當有新的behavior出現,只需要增加一個class即可,並不會重新設計。

注意到上面在分析如何封裝時其實有一個分析的方式叫做共通性和可變性分析和抽象類別,
共通性分析就是尋找一些共同的要素,例如移動的行為,可變性分析則說明了物件之間不同的行為,例如飛,走,游。

在設計模式的解析與活用中提到

共通性分析尋找的是不可能隨時間而改變的結構,而可變性分析則要找到可能變化的結構,
從架構的視角來看,共通性分析為架構提供長效的要素,而可變性分析則促進適應實際使用所需。



從上面這張圖我們可以看出這樣的概念

  • 抽象類別(共通性):需要用甚麼介面來處理這個類別的所有責任
  • 衍生類別(可變性):對於這個指定的實作(這個變化),應該怎樣根據指定的規約來實作他

下面有關於使用抽象類別進行特殊化的好處,也就是繼承抽象的好處



我們發現這種設計模式,總是預先設計大概的雛形,這是否跟敏捷開發中不預先設想的想法衝突?

關於這個問題我們再進一步仔細思考,我認為在某些情況下我們的確不該預先設想,過於關注細節,我們應該觀察物件發生變化的可能,並且使用封裝的方式將變化封裝,然而我們必須注意的是,敏捷開發以及設計模式所關注的共同要點
  1. 無冗餘
  2. 可讀性
  3. 可測試性
無冗餘性

Kent Back Once and Only Once rule,他說明了功能只在一個地方實作,也就是同樣的程式碼不出現在第二個地方,避免出現重複的程式碼,消除重覆的好處在於,當功能需要更改時我們只需要更改一個地方,而且在更改時我們不需再去考慮是否有遺漏。
這種概念就跟依介面設計的概念不謀而合,找出變化,利用介面使程式碼高度內聚。

可讀性

也就是反應意圖,這如同依介面設計的概念,當我們使用介面時,我們就是利用了介面來傳遞我們的概念,例如  上面動物行為的例子中  behavior.move(),代表著動物執行了移動的動作
但是我們並不在乎動物是如何移動的,它反映了動物的意圖。

可測試性

TDD與依介面設計的概念也是一樣的,如果封裝的好,就會產生高內聚,鬆耦合的程式碼,
也會讓我們在寫測試的時候更加的方便。

其實敏捷開發與設計模式要求的都是

內聚: 程式碼更容易測試,因為程式碼只負責一個責任(SRP)
鬆耦合:由於需要關注的東西較少,所以在測試的時候不需要去在乎太多其他類別的東西
冗餘程式碼:冗餘程式碼過多會造成測試涵蓋率下降
可讀性好:可以更明確的表達意圖
封裝性好:鬆耦合,減少對其他物件的關注

小結

其實不管是設計模式或是敏捷開發,其實大家在乎的要點都是,如何開發出高品質的程式碼,
簡單的說,想辦法寫出高內聚,鬆耦合,封裝變化的程式碼就對了

沒有留言:

張貼留言