面向物件五大設計原則以及常見設計模式總結
儘管本人已經從事OOP程式設計好幾年,但對於OOP程式設計的很多精髓依舊瞭解不深。加之最近專案不緊,特抽出時間總結一些面向物件設計原則以及設計模式的相關內容,加深自己的理解同時也希望可以幫到其他人。
note:程式設計是一門技術更是一門藝術,藝術來源於生活又高於生活。下面介紹的很多東西很多都可以和我們的日常生活緊密結合起來,建議大家從身邊尋找原型。
一、三大特性
面向物件的三大特性:封裝、繼承、多型。
封裝:封裝變化點,對上游透明化設計,解耦上下游之間的依賴
繼承:抽象出父類,將父類作為子類的模板,所有重複的程式碼都應該提到父類中去,而不是在每個子類中都重複。子類擁有父類所有非private的行為和屬性。注意,不要濫用繼承。
多型:同一操作作用於不同的物件,可以有不同的解釋,產生不同的執行結果,多型其實部分破壞了封裝的特性。
開發人員應該僅對程式中頻繁呈現出變化的那部分進行抽象,然而,抽象不是無限度的,拒絕抽象和抽象本身一樣重要。
降低軟體各個層級之間的耦合度,將業務邏輯與介面邏輯分開,降低他們之間的耦合度,只有分離開,才可以達到容易維護和擴充套件。
封裝、繼承、多型也是為了降低程式的耦合度。
二、五大設計原則(SOLID原則)
1、單一職責原則(SRP)
單一職責原則:就一個類而言,應該僅有一個引起它變化的原因。
職責可以理解為變化點。
該原則可以帶來以下幾點好處:
(1)降低類維護的難度
(2)降低耦合度,避免職責之間的相互影響
(3)降低類的複雜度
(4)降低單元測試難度,方便效果迴歸
2、修改-封閉原則(OCP)
對於擴充套件是開放的,對於修改是封閉的,對於修改封閉是為了避免修改會對之前的功能有影響。
面對需求,對於程式的改動是通過新增程式碼實現的,而不是更改現有的程式碼。
該原則是面向物件設計的核心所在,遵從這個原則可以帶來面向物件所謂的可維護、可擴充套件、可複用、靈活性強的優點。
3、依賴倒置原則(DIP)
抽象不應該依賴於細節,細節應該依賴於抽象。簡單點說就是要針對抽象(介面)程式設計而不是實現程式設計。
A:高層模組不應該依賴於低層模組,兩個都應該依賴於抽象,可以是介面或者抽象類的抽象
B:抽象不應該依賴於細節,細節應該依賴於抽象。
4、里氏替換原則(LSP)
在軟體裡面,把父類替換成子類,程式的行為沒有變化。簡單點說,子型別必須能夠替換掉他們的父型別。
包含以下4層含義:
(1)子類可以實現父類的抽象方法,但是不能覆蓋父類的非抽象方法
(2)子類中可以增加自己特有的方法
(3)當子類覆蓋或實現父類的方法時,方法的前置條件(即方法的形參)要比父類方法的輸入引數更寬鬆
(4)當子類的方法實現父類的抽象方法時,方法的後置條件(即方法的返回值)要比父類更嚴格
5、介面分離原則(ISP)
控制各個模組之間通過介面進行呼叫,防止直接呼叫。
無論哪種設計模式,都是圍繞上面的五個原則展開的。
一個好模式(架構)的特點:易維護、易擴充套件、易複用,高內聚、都耦合,這樣可以最大限度的做到易維護、易擴充套件、已複用。
三、常見設計模式:
1、簡單工廠模式
對於上層遮蔽建立物件的細節,提供一種物件建立的介面,根據具體的策略建立對應的物件,最終給上層返回的是一個物件。
通常各個物件之間是有關係的,繼承自相同的父類或者有繼承鏈關係,只有這種在上次呼叫的時候才可以遮蔽這些不同物件直接方法呼叫的差異,呼叫同一個方法。
2、策略模式
封裝演算法,對上層遮蔽演算法的實現細節。
應用場景:在不同的時間應用不同的業務規則。
3、代理模式
為其他物件提供一種代理以控制對這個物件的訪問。
代理物件對上層隱層呼叫細節,代理物件的低層還是由原始者發起請求。
代理物件與被代理物件通常會實現相同的介面(抽象類),代理物件的方法體內實際還是呼叫了被代理物件的對應方法。
4、工廠方法模式
對於計算器工廠類而言,如果想要新增一個運算,需要修改工廠類以及新增一個運算類,而修改工廠類是違反擴充套件開發原則的。
工廠方法模式:定義一個用於建立物件的介面,讓子類決定例項化哪一個類。工廠方法使一個類的例項化延遲到其子類。
簡單工廠模式是隻有一個工廠類,而工廠方法是提供一個介面,然後衍生出多個子類工廠去實現該介面,在子類工廠裡面決定具體使用哪個型別進行物件的例項化。
對應到計算器,就是提供加減乘除四個工廠類,在四個工廠類中具體例項化加減乘除操作類。如果還需要新增一個取模運算,只需要實現介面生成一個新的取模工廠類,然後在該工廠裡實例化取模操作類(該類也要新增)。
5、原形模式
用原形例項指定建立物件的種類,並且通過拷貝這些原形建立新的物件。
原形模式的核心是拷貝,通過拷貝避免了通過建構函式建立物件,對效能有提升。
目前PHP語言裡面的引用複製即是採用的該種方式:與原物件指定同一塊地址單元,只有當物件的屬性值發生變化時才會為其分配一塊新的記憶體單元,阻止或推遲了物件記憶體單元的分配。
6、模板方法模式
定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個演算法的結構I課重定義該演算法的某些特定步驟。
該模式是通過把不變的行為搬移到超類中,去除子類中的重複程式碼來體現它的優勢,提供了一個很好的程式碼複用的平臺。
7、外觀(門面)模式
為子系統中的一組介面提供一個一致的介面,此模式定義了一個高層介面,這個介面使得這個子系統更加容易使用。
8、建造者模式
將一個複雜物件的構建與他的表示分離,使得同樣的構建過程可以建立不同的表示。
將構造細節對上層遮蔽,上層只需要關注與細節即可。
9、觀察者模式
觀察者模式又叫做釋出-訂閱模式。
該模式定義了一種一對多的依賴關係,讓多個觀察者物件同時監聽某一個主題物件。這個主題物件在狀態發生改變時,會通知所有觀察者物件,使他們能夠自動更新自己。
觀察者訂閱主題物件(通知者)釋出的狀態變更並及時更新自己的狀態。
該模式所做的工作其實就是在解耦,讓耦合的雙方都依賴於抽象而不是依賴於細節。從而使得各自的變化都不會影響另一邊的變化。
一般用一個抽象類來定義主題物件(通知者),這個抽象類中儲存了訂閱了該主題物件的觀察者,並可以隨時增加/移除觀察者,並在狀態變更時向訂閱者釋出訊息。可以實現多個子類來產生多個釋出者(通知者)。
一般也用一個抽象類來定義觀察者,這個類中定義了觀察者訂閱的釋出者(抽象類),以及接收到釋出者傳送的通知時如何響應,具體響應的內容由各個子類去實現。
10、抽象工廠模式
提供一個建立一系列相關或者相互依賴物件的介面,無需指定他們具體的類。
11、狀態模式
當一個物件的內在狀態改變時允許改變其行為,這個物件看起來像是改變了其類。
12、介面卡模式
將一個類的介面轉換成客戶希望的另外一個介面。Adapter模式使得原本由於介面不相容而不能一起工作的哪些類可以一起工作。
C#中關於資料來源 資料庫有DataAdapter介面卡。
適用場景:雙方都不太容易修改的時候再使用介面卡模式適配,可以用於開發設計和專案維護階段。
13、迭代器模式
提供一種方法順序訪問一個聚合物件中各個元素,而不暴露該物件的內部表示。
各個語言中的foreach for遍歷即是常見的迭代器模式運用。
14、單例模式
保證一個類僅有一個例項,並提供一個訪問訪問它的全域性訪問點。
在類中定義一個私有的建構函式和物件變數,並提供一個public型別的靜態方法,在這個靜態方法中完成物件是否建立的判斷(根據物件變數判斷)以及建立。
多執行緒併發訪問時可能會造成多個物件的產生,可以通過鎖來解決。
15、橋接模式
將抽象部分與他的實現部分分離,使他們都可以獨立地變化。
16、直譯器模式
給定一個語言,定義它的文法的一種表示,並定義一個直譯器,這個直譯器使用該表示來解釋語言中句子。
瀏覽器就是html語言以及js語言的直譯器,php-cgi就是php語言的直譯器。
上面只是簡要列舉了一些常見的設計模式,具體各個設計模式如何使用後期會逐步完善。