【設計模式】之六大設計原則

原文http://geek.csdn.net/news/detail/249046

在軟件開發中有很多的設計模式,也有一些很高冷,談談我對軟件設計的理解,以及讓一些設計原則接地氣。

瞭解設計模式的朋友們,想必都聽說過“六大設計原則”吧。其實最經典的 23 種設計模式中或多或少地都在使用這些設計原則,也就是說,設計模式是站在設計原則的基礎之上的。所以在學習設計模式之前,很有必要對這些設計原則先做一下了解。

GoF(四人幫),傳說中的四位大神們,他們聯手搞出了一套設計模式,堪稱 OOD(面向對象設計)的經典之作!震驚了整個軟件開發領域。但這四個老傢伙非常怪異,總是喜歡顯擺一些高深的理論,甚至有時候不說人話,十分讓人費解。

除了最經典的六大設計原則以外,還有一些其他的設計原則也非常重要。我將儘可能地解釋這些晦澀的理論,希望看完之後,會讓您對這些設計原則稍微加深一些理解。若有不正確的地方,懇請大家指正!

  • 六大設計原則

先看一幅圖吧:

這幅圖清晰地表達了六大設計原則,但僅限於它們叫什麼名字而已,它們具體是什麼意思呢?下面我將從原文、譯文、理解、應用,這四個方面分別進行闡述。

1.單一職責原則(Single Responsibility Principle - SRP)

原文:There should never be more than one reason for a class to change. 
譯文:永遠不應該有多於一個原因來改變某個類。 
理解:對於一個類而言,應該僅有一個引起它變化的原因。說白了就是,不同的類具備不同的職責,各施其責。這就好比一個團隊,大家分工協作,互不影響,各做各的事情。 
應用:當我們做系統設計時,如果發現有一個類擁有了兩種的職責,那就問自己一個問題:可以將這個類分成兩個類嗎?如果真的有必要,那就分吧。千萬不要讓一個類乾的事情太多!

2.開放封閉原則(Open Closed Principle - OCP)

原文:Software entities like classes, modules and functions should be open for extension but closed for modifications. 
譯文:軟件實體,如:類、模塊與函數,對於擴展應該是開放的,但對於修改應該是封閉的。 
理解:簡言之,對擴展開放,對修改封閉。換句話說,可以去擴展類,但不要去修改類。 
應用:當需求有改動,要修改代碼了,此時您要做的是,儘量用繼承或組合的方式來擴展類的功能,而不是直接修改類的代碼。當然,如果能夠確保對整體架構不會產生任何影響,那麼也沒必要搞得那麼複雜了,直接改這個類吧。

3.里氏替換原則(Liskov Substitution Principle - LSP)

原文:Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it. 
譯文:使用基類的指針或引用的函數,必須是在不知情的情況下,能夠使用派生類的對象。 
理解:父類能夠替換子類,但子類不一定能替換父類。也就是說,在代碼中可以將父類全部替換爲子類,程序不會報錯,也不會在運行時出現任何異常,但反過來卻不一定成立。 
應用:在繼承類時,務必重寫(Override)父類中所有的方法,尤其需要注意父類的 protected 方法(它們往往是讓您重寫的),子類儘量不要暴露自己的 public 方法供外界調用。

該原則由麻省理工學院的 Barbara Liskov 女士提出,她是美國第一位獲取計算機博士學位的女性,曾經也獲得過計算機圖靈獎。

4.最少知識原則(Least Knowledge Principle - LKP)

原文:Only talk to you immediate friends. 
譯文:只與你最直接的朋友交流。 
理解:儘量減少對象之間的交互,從而減小類之間的耦合。簡言之,一定要做到:低耦合,高內聚。 
應用:在做系統設計時,不要讓一個類依賴於太多的其他類,需儘量減小依賴關係,否則,您死都不知道自己怎麼死的。

該原則也稱爲“迪米特法則(Law of Demeter)”,由 Ian Holland 提出。這個人不太願意和陌生人說話,只和他走得最近的朋友們交流。

5.接口隔離原則(Interface Segregation Principle - ISP)

原文:The dependency of one class to another one should depend on the smallest possible interface. 
譯文:一個類與另一個類之間的依賴性,應該依賴於儘可能小的接口。 
理解:不要對外暴露沒有實際意義的接口。也就是說,接口是給別人調用的,那就不要去爲難別人了,儘可能保證接口的實用性吧。她好,我也好。 
應用:當需要對外暴露接口時,需要再三斟酌,如果真的沒有必要對外提供的,就刪了吧。一旦您提供了,就意味着,您將來要多做一件事情,何苦要給自己找事做呢。

6.依賴倒置原則(Dependence Inversion Principle - DIP)

原文:High level modules should not depends upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions. 
譯文:高層模塊不應該依賴於低層模塊,它們應該依賴於抽象。抽象不應該依賴於細節,細節應該依賴於抽象。 
理解:應該面向接口編程,不應該面向實現類編程。面向實現類編程,相當於就是論事,那是正向依賴(正常人思維);面向接口編程,相當於通過事物表象來看本質,那是反向依賴,即依賴倒置(程序員思維)。 
應用:並不是說,所有的類都要有一個對應的接口,而是說,如果有接口,那就儘量使用接口來編程吧。

將以上六大原則的英文首字母拼在一起就是 SOLID(穩定的),所以也稱之爲 SOLID 原則。

只有滿足了這六大原則,才能設計出穩定的軟件架構!但它們畢竟只是原則,只是四人幫給我們的建議,有些時候我們還是要學會靈活應變,千萬不要生搬硬套,否則只會把簡單問題複雜化,切記!

  • 補充設計原則

1.組合/聚合複用原則(Composition/Aggregation Reuse Principle - CARP)

當要擴展類的功能時,優先考慮使用組合,而不是繼承。這條原則在 23 種經典設計模式中頻繁使用,如:代理模式、裝飾模式、適配器模式等。可見江湖地位非常之高!

2.無環依賴原則(Acyclic Dependencies Principle - ADP)

當 A 模塊依賴於 B 模塊,B 模塊依賴於 C 模塊,C 依賴於 A 模塊,此時將出現循環依賴。在設計中應該避免這個問題,可通過引入“中介者模式”解決該問題。

3.共同封裝原則(Common Closure Principle - CCP)

應該將易變的類放在同一個包裏,將變化隔離出來。該原則是“開放-封閉原則”的延生。

4.共同重用原則(Common Reuse Principle - CRP)

如果重用了包中的一個類,那麼也就相當於重用了包中的所有類,我們要儘可能減小包的大小。

5.好萊塢原則(Hollywood Principle - HP)

好萊塢明星的經紀人一般都很忙,他們不想被打擾,往往會說:Don’t call me, I’ll call you. 翻譯爲:不要聯繫我,我會聯繫你。對應於軟件設計而言,最著名的就是“控制反轉”(或稱爲“依賴注入”),我們不需要在代碼中主動的創建對象,而是由容器幫我們來創建並管理這些對象。

  • 其他設計原則

1.不要重複你自己(Don’t repeat yourself - DRY)

不要讓重複的代碼到處都是,要讓它們足夠的重用,所以要儘可能地封裝。

2.保持它簡單與傻瓜(Keep it simple and stupid - KISS)

不要讓系統變得複雜,界面簡潔,功能實用,操作方便,要讓它足夠的簡單,足夠的傻瓜。

3.高內聚與低耦合(High Cohesion and Low Coupling - HCLC)

模塊內部需要做到內聚度高,模塊之間需要做到耦合度低。

4.慣例優於配置(Convention over Configuration - COC)

儘量讓慣例來減少配置,這樣才能提高開發效率,儘量做到“零配置”。很多開發框架都是這樣做的。

5.命令查詢分離(Command Query Separation - CQS)

在定義接口時,要做到哪些是命令,哪些是查詢,要將它們分離,而不要揉到一起。

6.關注點分離(Separation of Concerns - SOC)

將一個複雜的問題分離爲多個簡單的問題,然後逐個解決這些簡單的問題,那麼這個複雜的問題就解決了。難就難在如何進行分離。

7.契約式設計(Design by Contract - DBC)

模塊或系統之間的交互,都是基於契約(接口或抽象)的,而不要依賴於具體實現。該原則建議我們要面向契約編程。

8.你不需要它(You aren’t gonna need it - YAGNI)

不要一開始就把系統設計得非常複雜,不要陷入“過度設計”的深淵。應該讓系統足夠的簡單,而卻又不失擴展性,這是其中的難點。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章