最初發表在:http://www.farproc.com/Article/ShowArticle.asp?ArticleID=187
找出變化的東西,封裝它!
"Find what varies and encapsulate it."
最近在學習 Alan Shalloway & James R. Troott 的 Design Patterns Explained (《設計模式解析》),於是隨手記下一些東西。
該書在第8章 Expanding Our Horizons 中講“封裝(encapsulation)”時提到一個封裝的原則是“Find what varies and encapsulate it.(找出變化的東西,封裝它)”對我的啟發很大。在此前,我對封裝的理解也僅僅是“資料隱藏(Data Hiding)”,最多能想到的是“細節隱藏(Details Hiding,這個是我自創的^_^)”,而真正的“封裝”是"any kind of hiding(任何形式的隱藏)"!!
裡面有一個例子,非常好:
比如為不同的動物的特性建模,需求如下:
不同種類的動物,腿的個數是不一樣的。
Animal 對象必須包含該資訊。
不同種類的動物,運動方式不同。
Animal 對象必須能夠返回在特定的地形中,從一個地方運動到另一個地方所需的時間。
處理“腿的個數”這個問題時典型的辦法就是用一個資料成員(data member)來儲存該資訊,用兩個成員方法(methods)來存取該值。“行為的不同”(在這裡就是運動方式)該怎麼設計呢?
假如說有兩種運動:“走(walk)”和“飛(fly)”,需要兩段不同的代碼來表現。傳統的方式可能是這麼設計的:
1) 給Animal類添加一個資料成員用於判斷當前Animal對象的運動方式
或者,
2) 從Animal繼承下來兩個獨立的類,一個會walk,一個會fly
但是這些處理方式存在問題:
緊偶合:在第一種設計(添加一個標誌成員,大概還需要一個switch來配合處理)中,如果這個標誌成員還有別的用途的話,將導致“緊偶合”。代碼也很亂。
太多的細節:第二種設計需要我控制Animal的子類。我還不能控制那些既會“走”又會“飛”的傢伙。
第三種設計:Animal類包含一個有適當運動方式的對象(have the Animal class contain an object that has the appropriate movement behavior),如:
既然動物之間的差別在於“運動方式”,並且“everything is an object”,所以我們找出了變化的東西:“運動方式”,然後把它封裝起來!!
試想,後來又添加的一種動物:魚,它的運動方式是“遊(swim)”,我們只用從AnimalMovement繼承出來一個AnimalSwim運動方式就OK了,我還可以通過Animal類的介面控制所有的動物!如果是前兩種設計呢?switch….重複代碼…
"Find what varies and encapsulate it."