程序可以分爲健壯的程序(擴展性強&效率高&人性化)和虛弱的程序(擴展性弱&效率不高&很難操作)。那怎麼做程序才健壯呢?遵循設計原則。
原則的描述
設計原則不像設計模式那麼多,原則只有7個而已。。。如下:
單一職責原則(Single Responsibility Principle,SRP):
概念:就一個類而言,應該僅有一個引起他變化的原因。(把變與不變的東西分離開來)
適應場景:如一個動物類有運動和休息兩個職責,如果運動||休息責需要修改動物類都要修改,這樣就有兩個引起動物類變化的原因。
實現模式例子:把動物類細分爲動物運動類和動物休息類,這樣不管是運動功能需要修改還是休息功能需要修改都不會影響到另外的功能。
優點:修改一個功能時對其他功能的影響降低。
缺點:過分地遵循單一職責原則會產生職責擴散(產生大量的類),不過可以用一個大管家來管理。
里氏替換原則(The Liskov Substitution Principle,LSP):
概念:子類型必須能夠替換掉它們的父類型,而功能不變;子類可以擴展父類的功能,但不改變父類原有的功能。(繼承不要重寫方法)
適應場景:動物類有體力屬性和跑&進食兩個方法,一個獅子類繼承了動物類重寫了進食方法,跑方法必須有體力才成運行,動物類的進食方法增加體力。但獅子類的進食沒有增加體力。這獅子就跑不動了。。
實現模式例子:獅子類添加新的進食方法,而不是重寫進食方法。
優點:擴展對原來的功能的影響會降低。
缺點:只能實現編譯時多態,不能實現運行時多態。
依賴倒轉原則(Dependency Inversion Principle ,DIP):
概念:高層模塊不應該依賴底層模塊,兩者都應依賴抽象;抽象不應依賴細節,細節應依賴抽象。(面向接口編程)
適應場景:肉類和人類,中國人類有吃的方法需要肉類作爲參數。3天后中國人類都變成素食者,程序就實現不了。
實現模式例子:但如果原本吃方法的參數是食物抽象類就可以解決這個問題。新建一個菜類繼承食物類,把食物作爲吃方法的參數。就可以實現素食啦。。
優點:大大提高了程序的擴展性。
缺點:增加了抽象類和接口。其實個人感覺不是問題。
接口分離原則(Interface Segregation Principle, ISP):
概念:應當爲客戶提供儘可能小的單獨的接口,而不是大的總接口。(不能分得太小)
適應場景:接口1有10個功能,有AB兩個類實現它。但B類只需要3個功能。
實現模式例子:把這3個功能寫成一個接口,然後接口1繼承這接口。這樣B類就不用實現它不需要的功能。就是把接口的粒度放小。
優點:不需要編寫多餘的代碼,這多餘的代碼肯能會導致程序出錯。
缺點:和單一職責原則一樣會產生職責擴散。
合成/聚合複用原則(Composition/Aggregation Reuse Principle,CARP):
概念:要儘量使用合成/聚合,而不是繼承關係達到複用。(組合勝於繼承)
適應場景:一個很多內容的A類,只想修改A類的一個內容不懂其他東西。
實現模式例子:新建一個B類。創建A類屬性和相同的方法簽名,在方法裏調用相應的方法。(達:這種方法用於重構比較好)
優點:聚合不像繼承那麼複雜,也可以很好的擴展。
缺點:A類和B類的耦合度很高。
迪米特法則/最少知識原則(Law of Demeter/Least Knowledge principle,LKP):
概念:一個軟件實體應當與儘可能少的其它實體發生作用。(接口也算第三者)
適應場景:A類調用B類。(適合任何的解耦)
實現模式例子: 創建C類調用B類,A類調用C類。(B類創建實現一個接口)
優點:很好的解耦。
缺點:過度遵循此原則會有大量的第三者。
開-閉原則(Open Closed Principle, OCP):
概念:軟件模塊(類,模塊,函數等等)應該可以在不可修改的情況下擴展。(程序無法做到完全的關閉;但類可以做到,如後面說到的BaseDao。)
適應場景:任何場景。
實現模式例子:此原則跟前面的6種有所不同,此原則只是告訴我們要做到怎樣,但沒有說要怎樣做。。此模式更像是前面6種原則的結果。如果能把握好前面的6種原則擴展性自然就會加強。
優點:程序的擴展性。
缺點:無法完全實現,
原則間的關係
* LSP是DIP的基礎,DIP是LSP的重要補充。
*OCP與DIP是目標和手段的關係。OCP是目標, DIP是到達OCP的手段。DIP是對"抽象化"的最好規範;由於OCP依賴DIP,LSP是DIP的基礎,所以LSP也是OCP基礎。
*ISP也是OCP的一個重要手段。
溫情提示:除了OCP之外其他原則都要把握好“度”。