隨手扎
【心得筆記】設計模式:可覆用物件導向軟體基礎
1月9號把一本經典的書籍給看完了,這麼說其實也不太對,因為我幾乎略過所有程式相關的部份,至於原因待會會提到。個人並不是非常推薦這本書– 設計模式:可覆用物件導向軟體基礎 ,就連已經看過「深入淺出設計模式」的我,都認為其中有些描述有點難懂。不過,設計模式本就有其應用的環境(context),如過無法沈浸在其環境,就難裡理解為什麼使用這個模式。比較不好的是,有人反而為了使用模式,而用模式,沒有考慮到其環境是否適合。這本書我認為的價值,是可以釐清模式的價值,與一些被人捧上天的錯誤想法。
推薦指數:★★☆☆☆
(應該可以多給半顆拉!反正都是我的主觀判斷www)
那麼一樣,筆記一些我覺得值得紀錄的片段。也就是說我不會直接提到或說明任何設計模式。
筆記開始
請記住,這不是一本讀完一遍就可以束之高閣的書。我們希望你在軟體設計過程中反覆參閱此書,以獲取設計靈感。
– Page. 3
(這本書也不是讀完一遍…就能懂的吧……有些模式的理解,還是與經驗有關…)
我之後有打算參考其他資源,做一下一些已有模式的整理筆記。
什麼是設計模式
設計模式並不要求使用獨特的語言特性,也不採用那些足以使你的朋友或老闆大吃一驚的神奇的程式技巧。
– Page. 3
設計模式是一種想法,每個想法有所出入並無不可,重要的是設計模式是在某個環境下是個的方法,以及用來溝通的工具。儘管同一個想法,其實現細節也可能有很大的差異,但重要的是能夠用以交流想法。雖然想法並不需要程式語言獨特的特性支持,但有語言的支持,比較容易達成,也有一些語言本身的限制,某些設計模式難以實現,或實現起來不如不要。
程式設計語言的選擇非常重要,它將影響人們理解問題的出發點 。我們的設計模式採用了Smalltalk和C++層的語言特性,這個選擇實際上 决定了哪些機制可以方便地實現,而哪些則不能 。若我们採用過程式語言,可能就要包括諸如“繼承”、“封裝”和“多態”的設計模式。 相應地,一些特殊的物件導向程式語言可以直接支持我們的某些模式,例如:CLOS支持多方法 (multi-method)概念,這就减少了Visitor模式的必要性。事實上, Smalltalk和C++已有足够的差别来說明對某些模式一種語言比另一種語言表述起来更容易一些。
– Page. 11
我自己在寫Lisp和Python,對於Visitor模式就沒什麼印象,也可能只是我用到而不知道而已。但本書採用Smalltalk和C++來作為範例。C++是一個…我覺得一生恐怕難以真正學會的語言,至於Smalltalk…我身邊更是沒聽過有人在用,故對於兩個語言本身的理解不夠多的情況下,書中範例就便得可有可無,,這已是我不太推的原因。
你的設計應該對手頭的問題有針對性 ,同時對將來的問題和需求也要有足够的通用性。 你也希望避免重覆設計或盡可能少做重覆設計。有經驗的物件導向程式設計師會告訴你,要一下子就得到可覆用性和靈活性好的設計,即使不是不可能的至少也是非常困難的。 一个設計在最终完成之前常要被覆用好幾次,而且每一次都有所修改 。
– Page. 9
–
使用Abstract Factory、Prototype或Builder的設計甚至比使用 Factory Method的那些設計更靈活,但它們也更加複雜。 通常,設計以使用Factory Method開始,並且當設計者發現需要更大的靈活性時,設計便會向其他創建型模式演化 。當你在設計標準之間進行權衡的时候,了解多个模式可以给你提供更多的選擇餘地。
– Page. 98
–
解决任何問題都要從頭做起。他們更願意覆用以前使用過的解决方案。當找到一个好的解决方案,他們會一遍又一遍地使用。這些经验是他們成為内行的部分原因。因此,你會在許多物件導向系統中看到類和相互通信的對象(communicating object)的重復模式。
– Page. 9
–
如果你能記起以前問題的細節和怎麼解決它的,你就可以復用以前的經驗而不需要重新發現它。 然而,我们並没有很好紀錄下可供他人使用的軟體設計的經驗 。 這本書的目的就是將物件導向軟體設計經驗作為設計模式紀錄下来。
– Page. 9
一個設計模式很難一步到位,透過經驗的累積與紀錄,這個過程可能可以簡短。
我們並不認為這組設計模式是完整的和一成不變的,它只是我們目前對設計的思考的紀錄。
– Page. 3
在我後來學習的模式中,還包含IIFE、Monad等,其他還有用於平行處理設計的。而筆記…真的很重要,最近開了新GitHub Repo,今天早上還在搞…後來想想,算了反正本來就是給我自己看,自己的凌亂筆記用的,有興趣和時間在慢慢整理成給人看吧(Publish)!預計那裡的一些筆記也會整理後,寫來這邊。
本書的第二章節中,提出了一個文檔編輯器的設計。光一個軟體,就用到了諸多設計模式。此外,一些設計模式也是基於其他設計模式的基礎之上,也就是說,很多設計模式並不能夠單一來看。但多數,會希望其細節足夠抽象而無須在意。
MVC還使用了其他的設計模式,如:用来指定視圖缺省控制器的 Factory Method和用来增加視圖滾動的Decorator。但是MVC的主要關係還是由Observer、Composite和Strategy三個設計模式给出的。
– Page.12
設計模式的基本要素
一般而言,一个模式有四个基本要素
- 模式名稱(pattern name)
- 問題(problem)
- 解决方案 (solution).
- 效果(consequences)
– Page. 10
不過比起來…我覺得最好可以以一個更簡單的方式去記憶為好。要記憶這四個要素,目前我還有些困難,或許只要簡單描述模式目的與作用,以及名稱別名即可。像是…工廠模式:抽象物件(商品)產生的方法,最終會回傳(輸出)一個指定的物件。
物件導向設計方法學支持許多設計方法。你可以寫出一个問題描述,挑出名詞和動詞, 進而創建相應的類別和方法;或者,你可以關注於系統的協作和職責關係;或者, 你可以對現實世界建模,再將分析時發現的對象轉化至設計中。至于哪一種方法最好,並無定論 。
– Page. 17
覺得還可以更好…不過:
出發點的不同會產生對什麼是模式和什么不是模式的理解不同。 一個人的模式對另一個人来說可能只是基本構造部件 。本書中我們將在一定的抽象層次上討論模式
– Page. 10
同樣的,我認為每個想法有所出入並無不可。
在設計模式之後
- 設計模式比框架更抽象
框架能够用程式碼表示,而設計模式只有其實例才能表示為程式碼。框架的威力在於它們能够使用程式設計語言寫出來,它們不僅能被學習,也能被直接執行和覆用。而本書中的設計模式在每一次被復用時,都需要被實現。設計模式還解释了它的意圖、權衡和設計效果。
–Page. 27
是的,這部份提了4點,我認為第一點最為重要。一個框架通常內含諸多設計方法,並且是已經存在的工具,但理解為什麼也很重要。
- 選擇模式參與者的名字,使它們在應用上下文中有意義。設計模式參與者的名字通常過于抽象而不会直接出現在應用中
– Page. 28
–
關於設計模式,如果不提一下它們的使用限制,那麼關於怎樣使用它們的討論就是不完整的。設計模式不能够随意使用 。通常你通過引入额外的間接層次獲得靈活性和可變性的同時,你也使設計變得更複雜/或犧牲了一定的性能。一個設計模式 只有當它提供的靈活性是真正需要的时候,才有必要使用 。
– Page. 29
–
這些設計模式也能提高你的設計水平。它們為你提供一些常見問題的解决方案。當然,如果你長期從事物件導向系統的工作,遲早你也會自己學到這些設計模式。但通過本書你可以學得更快。學好這些模式將有助於一个新手做出像專家一樣的設計。
– Page.241
–
一个成熟的設計方法不僅要有設計模式,還可有其他類型的模式,如分析模式,用户界面設計模式,或者性能調節模式等等 。但是設計模式是最主要的部分,這在以前却被忽略了。 – Page.241
–
在此過程中,我們改動了一些模式的名稱。“Wrapper”變成了“Decorator”,“Glue”變成了“Facade”,“Solitaire”變成了“ Singleton”,以及“Walker”變成了“Visitor”,並刪掉了幾個看起来不那麼重要的模式。不過自1992年以來,這个分類體系中包含哪些模式没有多大變化,但各模式本身卻有了巨大改進。
實際上,注意到某些東西是一个模式還是整个工作中相對容易的部分。我們四個人都经常從事建造物件導向系統的工作,發現當接觸到足够多的系統時,發現模式並不困难。然而描述模式卻要困难得多。
當你回過頭來看你已经建好的一些系统时,會發現所做的工作中就存在着模式。但是,要很好地描述它们以使不熟悉的人也能理解並意識到它們為什麼重要就很困难了。專家們能立即從我們模式的早期版本中意識到它們的價值,但也只有這些實際已經用過這些模式的人才能理解它們。
– Page.243
–
模式是問題的解决方案,是可以被重複使用的技術手段,這很容易明白;困難的是知道在什么情况下使用这个模式才是恰當的,也就是要課話這個模式所針對問題及其上下文,只有在這樣的上下文中,这個模式才是最優解。一般而言,了解“做什麼”要比“為什麼”來的容易;而一个模式的“為什麼”就是它要解决的問題。了解一个模式的目的也是重要的,它可以帮助我們選擇要使用的模式,也可以幫助我們理解已有系统的設計。作為一个模式的作者,即使你已經知道了解决方案,你還是必須回過頭來確定並刻畫該模式所解决的问题。
– Page. 243
一些設計模式
動態綁定 是指發送的請求直到運行時刻才受你的具體的實現的約束。因而,在知道任何有正確界面(interface)的對象都將接受此請求時,你可以寫一個一般的程序,它期待著那些具有該特定界面的對象。進一步講,動態绑定允許你在運行時刻彼此替換有相同接口的物件。这種可替換性就稱為多態(polymorphism),它是物件導向系統中的核心概念之一 – Page. 18
多態(polymorphism)是許多模式的基礎。通常,使用interface會比使用繼承來的更靈活,但有可能因此增加程式碼行數。
物件組合是類型繼承之外的另一種複用選擇。新的更複雜的功能可以通過組裝或组合物件來獲得。物件組合要求被組合的物件具有良好定義的界面。這種覆用風格被稱為黑箱覆用(black-box reuse),因為物件的内部細節是不可見的。物件只以“黑箱”的形式出现。
– Page. 21
ADAPTER(适配器)—类对象结构型模式
意图
将一个类的接口转换成客户希望的另外一个接口。 A d a p t e r模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。别名
包装器 Wr a p p e r。动机
有时,为复用而设计的适用性
以下情况使用A d a p t e r模式• 你想使用一个已经存在的类,而它的接口不符合你的需求。
• 你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。
• (仅适用于对象 A d a p t e r)你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。-- Page.100
–
以下一些情况使用 B r i d g e模式:
• 你不希望在抽象和它的实现部分之间有一个固定的绑定关系。例如这种情况可能是因为,在程序运行时刻实现部分应可以被选择或者切换。
• 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。这时 B r i d g e模式使你可以对不同的抽象接口和实现部分进行组合,并分别对它们进行扩充。
• 对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译。 • (C + +)你想对客户完全隐藏抽象的实现部分。在 C + +中,类的表示在类接口中是可见的。 • 正如在意图一节的第一个类图中所示的那样,有许多类要生成。这样一种类层次结构说明你必须将一个对象分解成两个部分。 R u m b a u g h称这种类层次结构为“嵌套的普化”(nested generalizations)。
• 你想在多个对象间共享实现(可能使用引用计数),但同时要求客户并不知道这一点。一个简单的例子便是 C o p l i e n的S t r i n g类,在这个类中多个对象可以共享同一个字符串表示( S t r i n g R e p)。