文章目錄
- 單一職責原則
- 開放封閉原則
- 裡氏代換原則
- 依賴倒轉原則
- 迪米特法則
引言
設計模式是軟體工程的基石。只有精通了設計模式,才敢說真正理解了軟體工程。可以說,設計模式是每一個架構師所必備的技能之一。
設計模式的起源是物件導向程式設計思想,而物件導向設計的精髓是——抽象。物件導向通過類和對象來實現抽象,實現是產生了物件導向的三個重要機制:封裝,繼承,多態。正是這三個機制衍生出了各種各樣的設計模式。
物件導向系統的分析和設計實際上追求的就是兩點,一是高內聚,二是低耦合。這是我們軟體設計所追求的,因此無論是OO中封裝,繼承,多態,還是我們的設計模式的原則和執行個體都是在為這兩個目標努力著。
在物件導向系統的設計和開發中,我們已經積累了很多的原則,比如物件導向中的封裝繼承和多態,面向介面編程,優先使用組合而不是繼承,將抽象和實現分離的思想等等,在設計模式中你總是能看到他們的影子,特別是組合(委託)和繼承的差異帶來系統在耦合性上的差別,更是在設計模式多次涉及到。
設計模式體現的是一種思想,而思想則是指導行為的一切,理解和掌握了設計模式,並不是記住了23種(或更多)設計情境和解決方案策略(實際上這也是很重要的一筆財富),實際接受的是一種思想的熏陶和洗禮,等這種思想融入到了你的思想中後,你就會不自覺的使用這種思想去進行你的設計和開發,這一切才是最重要的。
原則單一職責原則
就一個類而言,應該僅有一個引起它變化的原因。如果一個類承擔的職責過多,就等於把這些職責耦合在一起,一個職責的變化可能會消弱或者抑制這個類完成其他職責能力。這種耦合會導致脆弱的設計,當變化發生時設計會遭到意想不到的破壞。如果你能夠想到多於一個的動機去改變一個類,那麼這個類就具有多於一個職責。
開放封閉原則
軟體實體可以擴充,但是不可修改。即對於擴充時開放的,對於修改時封閉的。面對需求,對程式的改動是通過增加代碼來完成的,而不是改動現有的代碼。當變化發生時,我們就建立抽象來隔離以後發生同類的變化。開放封閉原則是物件導向的核心所在。開放人員應對程式中呈現出頻繁變化的那部分做出抽象,拒絕對任何部分都刻意抽象及不成熟的抽象。
裡氏代換原則
一個軟體實體如果使用的是一個父類的話,那麼一定適用其子類。而且他察覺不出父類對象和子類對象的區別。也就是說:在軟體裡面,把父類替換成子類,程式的行為沒有變化。子類型必須能夠替換掉它們的父類型。
依賴倒轉原則
抽象不應依賴細節,細節應依賴抽象。即針對介面編程,不要對實現編程。高層模組不能依賴低層模組,兩者都應依賴抽象。依賴倒轉原則是物件導向的標準。
迪米特法則
如果兩個類不直接通訊,那麼這兩個類就不應當發生直接的相互作用。如果一個類需要調用另一個類的某個方法的話,可以通過第三個類轉寄這個調用。子啊類的結構設計上,每一個類都應該盡量降低成員的存取權限。該法則在適配器模式,解釋模式中有強烈的體現。
23種設計模式
|
類別 |
模式說明 |
|
建立型模式 |
Factory (原廠模式):用於同一基類的衍生類別對象(產品)。用一個工廠的衍生類別來建立一個產品的衍生類別,它們是一一對應的關係。 |
|
Abstract Factory(抽象原廠模式):用於建立不同基類的衍生類別對象(產品)。 |
|
Singleton(單例模式):保證一個類僅有一個執行個體,並提供一個訪問它的全域訪問點。 |
|
Prototype(原型模式):用原型執行個體指定建立對象的種類,並且通過拷貝這個原型來建立新的對象。 |
|
Builder(建造者模式):將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。 |
|
結構型模式 |
Bridge(橋接模式):將抽象部分與它的實現部分分離,使它們都可以獨立地變化。 |
|
Adapter(適配器模式):將一個類的介面轉換成客戶希望的另外一個介面。Adapter模式使得原本由於介面不相容而不能一起工作的那些類可以一起工作。 |
|
Decorator(裝飾模式):動態地給一個對象添加一些額外的職責。就擴充功能而言, 它比產生子類方式更為靈活。 |
|
Composite(組合模式):將對象組合成樹形結構以表示“部分-整體”的階層。它使得客戶對單個對象和綜合物件的使用具有一致性。 |
|
Flyweight(享元模式):運用共用技術有效地支援大量細粒度的對象。 |
|
Facade(面板模式):為子系統中的一組介面提供一個一致的介面。Facade模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。 |
|
Proxy(代理模式):為其他對象提供一個代理以控制對這個對象的訪問。 |
|
行為型模式 |
Template(模版):定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中。Template使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。 |
|
Visitor(訪問者模式):表示一個作用於某對象結構中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用於這些元素的新操作。 |
|
Strategy(策略模式):定義一系列的演算法,把它們一個個封裝起來, 並且使它們可相互替換。本模式使得演算法的變化可獨立於使用它的客戶。 |
|
State(狀態):允許一個對象在其內部狀態改變時改變它的行為。對象看起來似乎修改了它所屬的類。 |
|
Observer(觀察者模式):定義對象間的一種一對多的依賴關係,以便當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並自動重新整理。 |
|
Memento(備忘錄模式):在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象之外儲存這個狀態。這樣以後就可將該對象恢複到儲存的狀態。 |
|
Command(命令模式):將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日誌,以及支援可取消的操作。 |
|
Mediator(中介者模式):用一個中介對象來封裝一系列的對象互動。中介者使各對象不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立地改變它們之間的互動。 |
|
Chain of Responsibility(責任鏈模式):為解除請求的寄件者和接收者之間耦合,而使多個對象都有機會處理這個請求。將這些對象連成一條鏈,並沿著這條鏈傳遞該請求,直到有一個對象處理它。 |
|
Interpreter(解譯器模式):給定一個語言, 定義它的文法的一種表示,並定義一個解譯器, 該解譯器使用該表示來解釋語言中的句子。 |
|
Iterator(迭代器模式):提供一種方法順序訪問一個彙總對象中各個元素, 而又不需暴露該對象的內部表示。 |
建立型模式:抽象了執行個體化過程。它們協助一個系統獨立於如何建立,組合,管理和表示他的那些對象。所有的建立型模式本質上都是對對象的建立過程進行封裝。
建立型模式分為對象建立模式和類建立模式。所謂對象建立模型就是說將執行個體化的工作委託給另一個對象來做。
類建立模型,就是一種通過繼承改變被執行個體化的類。類建立型模式有兩個重要的特點:①用戶端端不知道功能實現的具體類是什麼(除非看源碼) ②隱藏了類的執行個體是如何被建立和放在一起的。這兩個重要的特點是通過抽象類別的虛介面技術做到的,這樣設計者可以決定何時何地如何建立和由誰來建立。關注對象的建立。建立型類模式將對象的部分建立工作延遲到子類,而建立型對象模式則將它延遲到另一個對象中。
建立型模式主要關注對象的建立過程,將對象的建立過程進行封裝,是用戶端可以直接得到對象,而不用去關心如何建立對象。
- 單例模式:用於得到記憶體中的唯一對象
- 原廠模式:用於建立複雜物件
- 抽象原廠模式:用於建立一組相關或相互依賴的複雜物件
- 建造者模式:用於建立模組化的更加複雜的對象
- 原型模式:用於得到一個對象的拷貝
結構型模式:顧名思義討論的是類和對象的結構,它採用繼承機制組合介面或實現(類結構型模式),或者通過組合一些對象,從而實現新的功能(對象結構型模式)。
這些結構型模式,它們在某些方面具有很大的相似性,仔細推敲,側重點卻各有不同。目的是整體協調,各個部分盡量減少耦合,以適應今後的變化。從程式的結構上解決模組之間的耦合問題。關注類或對象之間的組織關係,怎樣組織起來形成大的結構,主要使用繼承來組織介面或實現。
結構型類模式使用繼承機制來組合類別,而結構型對象模式則描述了對象的組裝方式。
行為型模式:對類或對象怎樣互動和怎樣分配職責進行描述。抽象出某個行為,使得整個過程更簡單。關注類或對象之間的互動和職責分配(就是用來幹什麼)。
行為型類模式使用繼承描述演算法和控制流程,而行為型對象模式則描述一組對象怎樣協作完成單個對象所無法完成的任務。
建立型模式和結構型模式強調的都是靜態類實體之間的關係,行為型模式著力解決的是類實體之間的通訊關係。
類之間的關係
類間關係有很多種,在大的類別上可以分為兩種:縱向關係,橫向關係。縱向關係就是繼承關係。橫向關係按照UML的建議大體可以分為四種:
|
|
UML標記法 |
關係 |
|
依賴(Dependency) |
虛線+箭頭( - - ->) |
...use a ... 用(為函數中的參數)具有偶然性。表現在代碼層面,為類B作為參數被類A在某個method方法中使用;局部變數。
單向依賴(--->) |
|
關聯(Association) |
實線+箭頭(→) |
...has a ... 有 。具體表現在,成員變數和參數。若類A單向關聯指向類B,則在類A中存在一個屬性B b。
單向關聯(→),雙向關聯(─),自關聯
依賴和關聯的區別:一個是使用,一個是擁有;關聯可以是雙向的,而依賴必須是單向的。 |
|
彙總(Aggregation) |
空心菱形+實線+箭頭(◇→) |
... has a ... 有。 彙總是關聯關係的一種特例,它體現的是整體與部分的關係,即has-a的關係。此時整體與部分之間是可以分離的,它們具有各自的生命週期。class A {...} class B { A* a; .....}
當類之間有整體--部分關係的時候,要用彙總、組合。 |
|
組合(Composition) |
實心菱形+實線+箭頭(◆→) |
... is a part of ...組成,組合是關聯關係的一種特例。整體和部分是不可分割的,它們具有相同的生命週期,組合類別要對被組合類別負責。class A{...} class B{ A a; ...}。繼承 是一種 a kind of);組合 一部分 a part of ) |
|
|
|
|
|
繼承(Generalization)
又稱 泛化關係 |
實線+空三角形(—△) |
...a kind of...是一種。子類繼承父類 |
|
實現(Implementation) |
虛線+空三角形(- - -△) |
子類實現抽象類別 |
它們的強弱關係:依賴 < 關聯 < 彙總 < 組合。彙總和組合是關聯的兩種具體關係,關聯包含組合和彙總。
設計模式專欄 23中設計模式C++源碼