編程原則

在21世紀的前幾年里,“Uncle Bob”Robert Martin引入了用OOP開發軟件的五條原

則,其目的是設計出更易于維護的高質量系統。無論是設計新應用程序,還是重構現有基

本代碼,這些SOLID原則都成為開發人員的地圖。

一 單一職責原則

單一職責原則(Single Responsibility Principle,SRP)指出,每個方法或類應當有且僅有

一個改變的理由。這意味著每個方法或類應當做一件事情,或者只有一項職責。在所有的

SOLID原則中,這是大多數開發人員感到最能完全理解的一條。嚴格來說,這也可能是違

反最頻繁的一條原則了。

二 開放閉合原則

開放/封閉原則(Open/Close Principle,OCP)是指軟件(方法、類等)應當開放擴充且關閉

修改。如果覺得它非常類似于繼承的OOP 原則,那就對了。它們之間的關系非常密切。事

實上,在.NET中OCP就是依賴于繼承的。

OCP的要點在于:作為開發人員,別人偶爾會向我們提供基類,偶爾也會為其他開發人

員生成基類框架,供其使用。這些使用者應當僅能使用這些基類,但不能對其進行修改。

這一點是必要的,因為其他使用者也可能依賴于由基類提供的功能。如果允許使用者修改

這些基類,可能會導致連鎖反應,不僅會影響到應用程序中的各方面,還會影響到企業內

的應用程序。還有一個問題,使用者有時可能會收到基類的升級版本。使用者在升級之前,

必須找出一種方法用來處理其對該基類先前版本中所做的自定義。

于是,問題變為:“那么,如果我需要修改這個基類的工作方式,那應當怎么做呢?”

OCP的另一部分中給出這一答案;基類應當開放,可進行擴充。在這里,擴充是指創建一

個由此基類繼承而來的派生類,它可以擴充或重載基類功能,以提供使用者所需要的特定

功能。這樣,使用者就能使用類的修改版本,而不會影響到類的其他使用者。使用者還可

以在將來更輕松地使用基類的升級版本,因為他們不用擔心丟失自己的修改內容。

三 里氏代換原則

繼承對于OCP,就相當于多態性對于里氏替換原則(Liskov Substitution Principle,LSP)。

LSP 規定:用超類代替應用程序中使用的對象時,應當不會破壞應用程序。這通常也被稱

為“契約式設計(design by contract)”。

回想前面的多態性示例,ComputePay 方法使用了Employee 類型的列表,其中Employee

就是基類型(超類型)。Salary、Hourly 和Seasonal 類都是從Employee 繼承而來,因此它們

是Employee 的子類型。

根據LSP,即使已經將列表聲明為Employee 的列表,也仍然可以用Salary、Hourly

和Seasonal 的具體實例來填充它。因為有了繼承,它們都支持Employee 聲明的相同契約(公

共的方法集或API)。應用程序可以對該列表進行迭代,并調用那些在列表中各個項目的

Employee 上定義的方法,不需要知道或特別關心它們都是什么類型。如果它們支持契約,

該調用就是合法的。

四 接口分離原則

到目前為止,已經在示例中使用了基于類的繼承,但還沒有過多地討論接口。回想一

下,接口就是在代碼中定義的契約,而類同意實現這一契約。這份協議要求類來為接口中

定義的所有方法提供實現。至于如何實現方法,則由這個類來決定,只要它遵守契約,支

持接口中的定義即可。接口是.NET中功能非常強大的功能;它們對繼承和多態的支持方式

與類相同。

接口分離原則(Interface Segregation Principle,ISP)規定,不應當強制客戶端依賴于其

不使用的接口。例如,銀行系統可能有一個用于評估信用申請的服務。為便于討論,假定

該服務不僅處理有質押信用(車船貸款、抵押),也處理無質押信用(信用卡、信用證、股票

信用額度)。如果正在開發一個客戶端,用于幫助從事汽車代理的金融專員為其客戶獲得汽

車貸款,則只需要關注汽車貸款的申請即可,無需考慮有關這一服務的任何其他事情。如

果沒有ISP,應用程序可能必須了解其他方法。

盡管乍看起來這并沒有什么,但它至少是增加了應用程序的復雜性,因為據以進行開

發的API中會有許多方法,遠遠超出所需要的。這樣可能會導致混淆,調用錯誤的方法還

可能會導致潛在的錯誤。還有一種可能,API中未被應用程序用到的部分可能會改變,而

這又會導致對終端的改變。這樣,因為沒用到、沒想用、甚至是根本就不關心的一些功能,

而增加了應用程序的維護成本。這種情況還存在安全風險。該應用程序是專用于汽車貸款

的。如果不道德的開發人員利用這個過于龐大的API來允許利用這一申請擔保其他類型的

信用,又該怎么辦呢?這種問題的嚴重性就不僅僅是代碼癱瘓、不可維護那么簡單了。

這一問題的解決方案就是專門針對客戶端的需要,為該服務創建幾個更小的、更精細

的接口。對于該示例應用程序,專門設計一個針對汽車貸款的接口是比較適當的做法。應

用程序可以用同一實現訪問同一個類,但這一次它使用了一個特定的接口,其中僅有實際

服務的一部分方法。這樣就降低了復雜性,將應用程序與API其他部分的修改隔離開來,

還有助于堵塞安全漏洞。

五 依賴倒轉原則

在完美世界里,應用程序的組件之間沒有耦合關系或綁定關系。開發人員也能夠改變

自己希望改變的任何東西,而不需要擔心在應用程序的其他地方出現缺陷,或者“不希望

存在的負面影響”。令人悲傷的是,我們并不是生活在完美世界里。因此,組件需要相互

綁定在一起,或者在某一點耦合,以構成實際應用程序。

依賴倒置原則(Dependency Inversion Principle,DIP)規定:代碼應當取決于抽象概念,

而不是具體實現;這些抽象不應當依賴于細節;而細節應當依賴于抽象。類可能依賴于其

他類來執行其工作(Employee 服務可能依賴于數據訪問組件向數據存儲中保存和檢索員工

信息)。但是,它們不應當依賴于該類的特定具體實現,而應當是它的抽象。也就是說,

Employee 服務不知道(或不關心)正在使用哪個具體的數據訪問組件——只有它的抽象或代

碼契約(或接口)支持那些用于保存和檢索員工所需要的方法。

顯然,這一概念會大大提高系統的靈活性。如果類只關心它們用于支持特定契約而不

是特定類型的組件,就可以快速而輕松地修改這些低級服務的功能,同時最大限度地降低

對系統其余部分的影響。在第6 章,還會看到如何利用這一概念來模擬這些依賴項,以進

行測試。有時,需要向類中提供這一低級服務的具體實現,以便這個類能夠完成自己的工

作。最常見的做法,特別是在.NET中使用TDD 的開發人員,就是依賴項注入(DI)模式。

============以上OOP軟件設計的SOLID原則==============

控制反轉原則

全局注冊樹

ORM 對象數據映射

合成聚合原則

啟動和執行分離原則

面向接口編程

配置加載 不是硬編程原則

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,991評論 19 139
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,778評論 18 399
  • 設計模式六大原則 設計模式六大原則(1):單一職責原則 定義:不要存在多于一個導致類變更的原因。通俗的說,即一個類...
    viva158閱讀 784評論 0 1
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,556評論 25 708
  • wait()系統調用.當調用進程的任意子進程終止時,會返回,由此可判斷子進程是否終止.wait系統調用存在以下幾個...
    王小寶wy閱讀 331評論 0 0