软件设计原则
1. 面向對象原則
(1)開閉原則
所謂開閉原則(Open Closed Principle, OCP)指的就是“軟件實體應當對擴展開放,對修改關閉”,簡單講就是軟件系統中包含的各種組件應該在不修改現有代碼的基礎上,引入新功能。開閉原則中“開”,是指對于組件功能的擴展是開放的,是允許對其進行功能擴展的;開閉原則中“閉”,是指對于原有代碼的修改是封閉的,即不應該修改原有的代碼。
(2)里氏替換原則
里氏替換原則(Liskov Substitution Principle,LSP)中說,任何基類可以出現的地方,子類一定可以出現。里氏替換原則可以理解為是對開閉原則的補充。實現開閉原則的關鍵步驟就是抽象化。而基類與子類的繼承關系就是抽象化的具體實現,所以里氏替換原則是對實現抽象化的具體步驟的規范。
(3)依賴倒置原則
依賴倒置原則(Dependence Inversion Principle,DIP)就是說要依賴于抽象,不要依賴于實現。也即意味著要針對接口編程,不要針對實現編程,具體表現上在應當使用接口和抽象類進行各種類型聲明以及數據類型的轉換。可以認為開閉原則與依賴倒置原則是目標和手段的關系。如果說開閉原則是目標,依賴倒轉原則是到達開閉原則的手段。如果要達到最好的開閉原則,就要盡量的遵守依賴倒置原則。
(4)單一職責原則
單一職責原則(Simple Responsibility Pinciple,SRP)強調一個類應該只有一個職責,并把職責定義為變化的原因。每一個職責都是變化的一個維度,如果一個類有一個以上的職責,這些職責就耦合在了一起,當一個職責發生變化時,可能會影響其它的職責,這就會導致脆弱的設計。另外,多個職責耦合在一起也會影響復用性。如果發現一個類有多于一個的職責,就應該通過分離接口等方式做到盡量解耦。
(5)接口隔離原則
關于隔離的含義就在于類之間的依賴關系應該建立在最小的接口上,一個類不應該依賴它不需用的接口。接口隔離原則(Interface Segregation Principle,ISP)就是說建立單一接口,不要建立臃腫龐大的接口。接口隔離原則與單一職責的審視角度是不相同的,單一職責要求的是類和接口職責單一,注重的是職責,這是業務邏輯上的劃分,而接口隔離原則要求接口盡量細化,接口的方法盡量少
以下五條原則一般被稱為面向對象領域的S(SRP).O(OCP).L(LSP).I(ISP).D(DIP)原則。
2. 組件設計原則
組件設計原則有時候也稱為分包(Package)原則。任何一個軟件系統都可以看做是一系列組件的集合,良好的組件設計能夠把系統分解為一些大小恰到好處的組件,從而使每個開發團隊都可以只關注單個的組件而無需關心整個系統。對于組件而言,最核心的關注點就是內聚(Cohesion)和耦合(Coupling),所謂內聚是指一個模塊內各個元素彼此結合的緊密程度,而耦合指的是一個軟件結構內不同模塊之間互連程度的度量。基于這兩個關注點,組件設計原則也包括組件內聚原則(Component Cohesion Principle)和組件耦合原則(Component Coupling Principle)兩大類。
組件內聚原則包括:
(1)重用-發布等價原則
重用-發布等價原則(Release-Reuse Equivalency Principle,REP)關注粒度,強調重用的粒度等于發布的粒度。重用-發布等價思想從用戶觀點的角度上為我們規范了組件設計的原則:在設計組件時,組件中應該包含的元素要么都可以重用,要么都不可以重用。
(2)共同封閉原則
共同封閉原則(Common Closure Principle,CCP)關注變化,即一個組件不應該包括多個引起變化的原因。組件中所有類對同一種性質的變化是共同封閉的,一個變化如果對一個封閉的組件產生影響,則將對該組件中的所有類產生影響,但對其他組件將不產生影響。該原則類似開放封閉原則,即對修改應該是封閉的,但對擴展應該是開放的。從這個角度看,組件越大越能滿足共同封閉原則。
(3)共同重用原則
共同重用原則(Common Reuse Principle,CRP)關注重用,認為一個組件中的所有類應該是共同重用的,如果重用了組件中的一個類就應該重用組件中的所有類。即放入一個組件中的類是不可分開的,僅僅依賴其中一部分類的情況不應該存在。顯然,根據共同重用原則,組件應該越小越好。
我們可以明顯看到共同封閉原則和共同重用原則具有互斥性,不同的原則面向不同的場景和生命周期。同樣,組件耦合原則也包含以下三條設計原則:
(4)無環依賴原則
無環依賴原則(Acyclic Dependencies Principle,ADP)認為在組件之間不應該存在循環依賴關系。通過將系統劃分為不同的可發布組件,對某一個組件的修改所產生的影響不應該必須擴展到其他組件。我們在后續的4.4.1節架構模式中會進一步探討當組件之間存在循環依賴時如何進行分析和消除。
(5)穩定抽象原則
穩定抽象原則(Stable Abstractions Principle,SAP)認為組件的抽象程度應該與其穩定程度保持一致。即一個穩定的組件應該也是抽象的,這樣該組件的穩定性就不會無法擴展。另一方面,一個不穩定的組件應該是具體的,因為他的不穩定性使其內部代碼更易于修改。
(6)穩定依賴原則
穩定依賴原則(Stable Dependencies Principle,SDP)認為被依賴者應該比依賴者更穩定。一個好的設計中的組件之間的依賴應該朝著穩定的方向進行。一個組件只應該依賴那些比自己更穩定的組件。在下圖中,我們認為組件X是穩定的,因為X被很多其他組件依賴,相當于責任擔當著。而X沒有依賴別的包,所有它具備很高的獨立性。同時,我們認為組件Y是不穩定的,因為Y沒有被其他的組件所依賴,但Y自身依賴很多別的組件。
?
3. 其他原則
除了面向對象和組件設計原則,業界還存在一批具有代表性的設計原則,包括:
(1)合成/聚合復用原則
合成/聚合復用原則(Composite/Aggregate Reuse Principle,CARP)強調在一個新的對象里面使用一些已有的對象,使之成為新對象的一部分,而新的對象通過向這些對象的委派達到復用這些對象的目的。也即推薦首先使用合成/聚合,合成/聚合則使系統靈活,其次才考慮繼承,達到復用的目的。而使用繼承時,要嚴格遵循里氏替換原則。有效地使用繼承會有助于對問題的理解,降低復雜度,而濫用繼承會增加系統構建、維護時的難度及系統的復雜度。所以合成/聚合復用原則在很多時候就體現為一句話,即組合由于繼承。
(2)迪米特法則
迪米特法則(Law of Demeter,LoD)認為一個軟件實體應當盡可能少的與其他實體發生相互作用。這樣,當一個模塊修改時,就會盡量少的影響其他的模塊,擴展也會相對容易。這是對軟件實體之間通信的限制,它要求限制軟件實體之間通信的寬度和深度。如果兩個類不必彼此直接通信,那么這兩個類就不應當發生直接的相互作用。如果其中的一個類需要調用另一個類的某一個方法的話,可以通過第三者轉發這個調用。設計模式中的門面模式和調停者模式實際上就是迪米特法則的具體應用。
(3)命令-查詢分離原則
當一個方法返回一個值來響應一個請求,它就具有查詢(Query)的性質;當一個方法要改變對象的狀態,它就具有命令(Command)的性質。通常,一個方法可能是純的Command模式或者是純的Query模式,或者是兩者的混合體。在設計接口時,如果可能,應該盡量使接口單一化,保證方法的行為嚴格的是命令或者是查詢,這樣查詢方法不會改變對象的狀態,沒有副作用,而會改變對象的狀態的方法不可能有返回值。這就是命令-查詢分離(Command-Query Separation,CQS)原則。查詢功能和命令功能的分離,有助于系統性能,也有利于系統的安全性。
(4)慣例優于配置原則
慣例優于配置(Convention over Configuration,CoC)原則簡單講就是將一些公認的配置方式和信息作為內部缺省的規則來使用。我們的應用只需要指定慣例外的信息即可,從而減少了大量配置信息,在大型系統中,過多的配置信息很多時候已經成為影響開發效率的一個源頭。目前流行的微服務開發框架SpringBoot就是該原則的典型表現。
(5)關注點分離原則
關注點分離(Separation of Concerns,SoC)原則就是指在軟件開發中,通過各種手段將問題的各個關注點分開。實現關注點分離的方法主要有兩種,一種是標準化,另一種是抽象與包裝。標準化就是制定一套標準,讓使用者都遵守它,這樣使用標準的人就不用擔心別人會有很多種不同的實現,使自己的程序不能和別人的兼容。另一方面,不斷地把程序的某些部分抽象并包裝起來,也是實現關注點分離的好方法。諸如組件、分層、面向服務等概念都是在不同的層次上做抽象和包裝以使得使用者不用關心它的內部實現細節。
?
如果對文章感興趣,可以關注我的微信公眾號:程序員向架構師轉型,或掃描下面的二維碼。
我出版了《系統架構設計:程序員向架構師轉型之路》、《向技術管理者轉型:軟件開發人員跨越行業、技術、管理的轉型思維與實踐》、《微服務設計原理與架構》、《微服務架構實戰》等書籍,并翻譯有《深入RabbitMQ》和《Spring5響應式編程實戰》,歡迎交流。
總結
- 上一篇: densepose的IUV图像I通道数字
- 下一篇: WinForm与脚本的交互