設計模式筆記

本文是《設計模式——可復用面對對象軟件的基礎》的筆記。

面對對象設計的幾個原則:
1.針對接口編程,而不是針對實現編程
2.優先使用對象組合,而不是類繼承
類繼承是在編譯時刻靜態定義的,可以直接使用,但無法在運行時刻改變從父類繼承的實現,并且父類的變化會引起子類的變化。所以類繼承最好是只繼承抽象類。
對象組合是通過獲得對其他對象的引用而在運行時刻動態定義的。并且,優先使用對象組合有助于保持每個類被封裝,并被集中在單個任務上。

1.創建型模式
創建性模式抽象了實例化過程。第一,它們都將關于該系統使用哪些具體的類的信息封裝起來。第二,它們隱藏了這些類的實例是如何被創建和放在一起的。
1.1 抽象工廠模式(abstract factory)
提供一個創建一系列相關或者相互依賴對象的接口,而無需指定它們具體的類。
適用范圍:
1.一個系統要獨立于它的產品的創建、組合和表示時
2.一個系統要由多個產品系列中的一個來配置時
3.當你要強調一系列相關的產品對象的設計以便進行聯合使用時
4.當你提供一個產品類庫,而只想顯示它們的接口而不是實現時
實現:
AbstractFactory:聲明一個創建抽象產品對象的操作接口。
ConcreteFactory:實現創建具體產品對象的操作。
AbstractProduct:為一類產品對象聲明一個接口。
ConcreteProduct:定義一個將被相應的具體工廠創建的產品對象,實現AbstractProduct接口
通常在運行時刻創建一個ConcreteFactory類的實例。AbstractFactory將產品對象的創建延遲到它的ConcreteFactory子類。
(抽象工廠為父類,子類為具體的工廠,調用不同子類產生不同的產品。)

1.2 生成器模式(builder)
將一個復雜對象的構建和它的表示分離,使得同樣的構建過程可以創建不同表示。
適用范圍:
1.當創建復雜對象的算法應該獨立于該對象的組成部分以及它們的裝配方式時
2.當構造過程必須允許被構造的對象有不同的表示時
實現:
Builder:定義創建一個Product對象各個部件的抽象接口
ConcreteBuilder:實現Builder的接口并提供獲取Product的接口
Director:構造一個使用Builder接口的對象
Product:表示被構造的對象
一般流程,通過Director解析構造Product所需要的參數并通過調用Builder接口調用具體的構造和裝配接口,最后從ConcreteBuilder獲得Product
(Director中有一個或多個Builder指針,指向Builder子類,由Director解析參數,再又Builder具體子類產生產品的全部或者部分再組裝。)

1.3 工廠方法模式(factory method)
定義一個用于創建對象的接口,讓子類決定實例化哪一個類。
適用范圍:
1.當一個類不知道它所必須創建的對象的類的時候
2.當一個類希望由它的子類來指定它所創建的對象的時候
實現:
Product:定義工廠方法所創建的對象的接口
ConcreteProduct:實現Product接口
Creator:聲明工廠方法,該方法返回一個Porduct類型的對象。Creator也可以定義一個工廠方法的缺省實現,它返回一個缺省的ConcreteProduct對象。所以可以是具體類也可以是抽象類
ConcreteCreator:重定義工廠方法以返回一個ConcreteProduct實例
通過調用Creator的工廠方法來創建一個Product對象
(工廠只知道何時創建產品,不知道該創建什么產品。抽象工廠的接口是給客戶用的,工廠方法的接口是給自己用的。例如 newProduct(){...createProduct();...};createProduct(){...};createProduct是工廠方法,由子類定義。)

1.4原型模式(Prototype)
用原型實例指定創建對象的種類,并且通過拷貝這些原型創建的對象。
適用范圍:
1.當要實例化的類是在運行時刻指定時
2.為了避免創建一個與產品類層次平行的工廠類層次
3.當一個類的實例只能有幾個不同狀態組合中的一種時
實現:
Prototype:聲明一個克隆自身的接口
ConcretePrototype:實現一個克隆自身的接口
調用Prototype的克隆接口獲得相應的ConcretePrototype
優點:
運行時刻增加和刪除產品
缺點:
拷貝和原型管理問題

1.5單例模式(Singleton)
保證一個類僅有一個實例,并提供一個訪問它的全局訪問點
適用范圍:
1.當類只能有一個實例而且客戶可以從一個眾所周知的訪問點訪問它時
實現:
Singleton:實現一個Instance操作,允許客戶訪問它的唯一實例。
客戶只能通過Singleton的Instance操作訪問一個Singleton的實例

2.結構型模式
結構型類模式采用繼承機制來組合接口或實現以獲得更大的結構。結構型對象模式描述了如何對一些對象進行組合從而實現新功能的一些方法。

2.1適配器模式(adapter)
將一個類的接口轉換成客戶希望的另外一個接口。
適用范圍:
1.希望使用一個已經存在但是接口不符合需求的類
2.希望創建一個可以復用的類,該類可以與其他不相關的類或者不可預見的類協同工作
3.希望使用一些已經存在的子類,但是不可能對每一個子類都進行子類化以匹配它們的接口,可以使用對象適配器適配它的父類接口
實現:
Target:定義Client使用的與特定領域相關的接口
Client:與符合Target接口的對象協同
Adaptee:定義一個已經存在的接口,這個接口需要適配
Adapter:對Adaptee的接口與Target接口進行適配
類適配器模式使用多重繼承進行匹配,Adapter同時繼承Target的接口和Adaptee的實現,用Adaptee的實現實現Target的接口。
對象適配器模式依賴對象組合進行匹配,Adapter繼承Target的接口,Adaptee作為Adapter的一個成員變量(或者其他對象組合形式)

2.2橋接模式(bridge)
將抽象部分與它的實現部分分離,使它們都可以獨立地變化。
適用范圍:
1.不希望在抽象和它的實現部分之間有一個固定的綁定關系。
2.類的抽象以及它的實現都能通過生成子類的方法加以擴充。
3.對一個抽象的實現部分的修改應對客戶不產生影響,即客戶的代碼不必重新編譯。
實現:
Abstraction:定義抽象類的接口,維護一個指向Implementor類型對象的指針
RefinedAbstraction:Abstraction的子類,擴充由Abstraction定義的接口
Implementor:定義實現類的接口
ConcreteImplementor:Implementor的子類,實現Implementor接口并定義它的具體實現
Abstraction將client的請求轉發給它的Implementor對象。
(Abstraction提供接口,Implementor提供實現,Abstraction包含Implementor指針成員變量。)

2.3組合模式(composite)
將對象組合成樹形接口以表示“部分-整體”的層次接口,可以使得用戶對單個對象和組合對象的使用具有一致性。
適用范圍:
1.想要表達對象的部分-整體層次結構。
2.希望用戶忽略組合對象和單個對象的不同,用戶統一地使用組合結構中的所有對象。
實現:
Component:為組合的對象聲明接口,聲明一個接口用于訪問和管理Component的字組件,在遞歸結構中可以定義一個用于訪問一個父部件的接口。
Leaf:在組合中表示葉節點對象,葉節點沒有子節點。在組合中定義圖元對象的行為。
Composite:定義有子部件的那些部件的行為,存儲子部件,在Component接口中實現與子部件有關的操作。
client:通過Component接口操縱組合部件的對象。
用戶使用Component類接口和組合結構中的對象進行交互。

2.4裝飾模式(decorator)
動態地給一個對象添加一些額外的職責。
適用范圍:
1.在不影響其他對象的情況下,以動態、透明的方式給單個對象添加職責。
2.處理那些可以撤銷的職責。
3.當不能采用生成子類的方法進行擴充時。
實現:
Component:定義一個對象接口,可以給這些對象動態地添加職責。
ConcreteComponent:定義一個對象,可以給這個對象添加一些職責。
Decorator:Component的子類,維持一個指向Component對象的指針,并定義一個與Component接口一致的接口。
ConcreteDecorator:向組件添加職責。
Decorator將請求轉發給它的Component對象,并有可能在轉發前后執行一些附加的操作。
(裝飾和被裝飾接口相同,調用裝飾的接口,裝飾在調用被裝飾接口前后添加一些操作。)

2.5外觀模式(facade)
為子系統中的一組接口提供一個一致的界面,Facade模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。
適用范圍:
1.為一個復雜子系統提供一個簡單接口。
2.客戶程序與抽象類的實現部分之間存在著很大的依賴性。
3.構建一個層次結構的子系統時,可以使用facade模式定義子系統中每層的入口點,讓相互依賴的子系統僅通過facade進行通訊,簡化它們的依賴關系。
實現:
Facade:知道哪些子系統負責處理請求,將客戶的請求代理給適當的子系統對象。
Subsystem classes:實現子系統的功能,處理由Facade對象指派的任務。
客戶程序通過發送請求給Facade的方式與子系統通訊,Facade將這些消息轉發給適當的子系統對象。
(Facade為一個子系統提供一組接口)

2.6享元模式(flyweight)
運用共享技術有效地支持大量細粒度的對象。
適用范圍:
一個應用程序適用了大量的對象,造成很大的存儲開銷。并且這些對象的大多數狀態都可變為外部狀態。如果刪除對象的外部狀態,那么可以用相對較少的共享對象取代很對組對象。應用程序不依賴于對象標識。
實現:
Flyweight:描述一個接口,通過這個接口flyweight可以接受并作用于外部狀態。
ConcreteFlyweight:實現Flyweight接口,并為內部狀態增加存儲空間。
UnsharedConcreteFlyweight:并非所有的Flyweight對象必須是可共享的。
FlyweightFactory:創建并管理flyweight對象。確保合理地共享flyweight。
Client:維持一個對flyweight的引用。計算或存儲flyweight的外部狀態。
flyweight執行所需的狀態必定是內部和外部狀態的結合。用戶不應直接對ConcreteFlyweight類進行實例化,只能從FlyweightFactory對象得到ConcreteFlyweight對象,這可以保證對它們適當地進行共享。
(將可以共享的對象共享,節省內存。)

2.7代理模式(proxy)
為其他對象提供一種代理以控制對這個對象的訪問。
適用范圍:
1.遠程代理(Remote Proxy)為一個對象在不同的地址空間提供局部代表。
2.虛代理(Virtual Proxy)根據需要創建開銷很大的對象。
3.保護代理(Protection Proxy)控制對原始對象的訪問,用于對象應該有不同的訪問權限的時候。
4.智能指引(Smart Reference)取代了簡單的指針,它在訪問對象時執行一些附加操作,例如計數、自動釋放、鎖等。
實現:
Proxy:保存一個引用使得代理可以訪問實體。若RealSubject和Subject的接口相同,Proxy會引用Subject。提供一個與Subject接口相同的接口,這樣代理就可以用來代替實體。控制對實體的存取,并可能負責創建和刪除它。其他功能依賴于代理的類型:Remote Proxy負責對請求及其參數進行編碼,并向不同地址空間中的實體發送已編碼的請求;Vritual Proxy可以緩存實體的附加信息,以便延遲對它的訪問;Protection Proxy檢查調用者是否具有實現一個請求所必須的訪問權限。
Subject:定義RealSubject和Proxy的共用接口,這樣就在任何使用RealSubject的地方都可以使用Proxy。
RealSubject:定義Proxy所代表的實體。
Proxy根據其種類,在適當的時候向RealSubject轉發請求。

3.行為模式
行為模式涉及到算法和對象間職責的分配。行為模式不僅描述對象或類的模式,還描述它們之間的通信模式,刻畫了在運行時難以跟蹤的復雜的控制流。行為類模式使用繼承機制在類間分派行為,而行為對象模式使用對象復合。

3.1職責鏈模式(chain of responsibility)
使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關系。將這些對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理它為止。
適用范圍:
1.有多個對象可以處理一個請求,哪個對象處理該請求運行時刻自動確定。
2.在不明確指定接收者的情況下,向多個對象中的一個提交一個請求。
3.可處理一個請求的對象集合應被動態指定。
實現:
Handler:定義一個處理請求的接口,(可選)實現后繼鏈。
ConcreteHandler:處理它所負責的請求,可訪問它的后繼者。如果可以處理請求,則處理之,否則轉給后繼者。
Client:向鏈上的具體處理者對象提交請求。
當客戶提交一個請求時,請求沿鏈傳遞直至有一個ConcreteHandler對象負責處理它。

3.2命令模式(command)
將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數化。
適用范圍:
1.需要抽象出待執行的動作以參數化某對象。可用回調函數表達這種參數化機制。
2.在不同的時刻指定、排列和執行請求。
3.支持取消操作。
4.支持修改日志,這樣當系統崩潰時,這些修改可以被重做一遍。
5.用構建在源于操作上的高層操作構造一個系統。類似于事物。
實現:
Command:聲明執行操作的接口
ConcreteCommand:將一個接收者對象綁定于一個動作,調用接收者相應的操作,以實現Execute
Client:創建一個具體命令對象并設定它的接收者。
Invoker:要求該命令執行這個請求。
Receiver:知道如何實施和執行一個請求相關的操作。
Client創建一個ConcreteCommand對象并指定它的Receiver對象。某Invoker對象存儲該ConcreteCommand對象。該Invoker通過調用Command對象的Execute操作來提交一個請求。若該命令是可撤銷的,ConcreteCommand就在執行Execute操作之前存儲當前狀態以用于取消該命令。ConcreteCommand對象對調用它的Receiver的一些操作以執行該請求。
ConcreteCommand就是被封裝的對象。

3.3解釋器模式(interpreter)
給定一個語言,定義它的文法的一種表示,并定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。
適用范圍:
1.當有一個語言需要解釋執行,并且你可將該語言中的句子表示為一個抽象語法樹時,可使用解釋器模式。
實現:
AbstractExpression( 抽象表達式):聲明一個抽象的解釋操作,這個接口為抽象語法樹中所有的節點所共享。
TerminalExpression(終結符表達式):AbstractExpression的子類。實現與文法中的終結符相關聯的解釋操作。句子中的每個終結符需要該類的一個實例。
NonterminalExpression(非終結符表達式):AbstractExpression的子類。對文法中的每一條規則都需要一個NonterminalExpression類。為每個符號都維護一個AbstractExpression類型的實例變量。為文法中的非終結符實現解釋(Interpret)操作。解釋(Interpret)一般要遞歸地調用表示那些對象的解釋操作。
Context(上下文):包含解釋器之外的一些全局信息。
Client:構建(或被給定)表示該文法定義的語言中一個特定的句子的抽象語法樹。該抽象語法樹由NonterminalExpression和TerminalExpression的實例裝配而成。調用解釋操作。
Client構建(或被給定)一個句子,它是NonterminalExpression和TerminalExpression的實例的一個抽象語法樹。然后初始化上下文并調用解釋操作。每一非終結符表達式節點定義相應子表達式的解釋操作。而各終結符表達式的解釋操作構成了遞歸的基礎。每一節點的解釋操作用上下文來存儲和訪問解釋器的狀態。

3.4迭代器模式(iterator)
提供一種方法順序訪問一個聚合對象中各個元素,而又不需暴露該對象的內部表示。
適用范圍:
1.訪問一個聚合對象的內容而無需暴露它的內部表示。
2.支持對聚合對象的多種遍歷。
3.為遍歷不同的聚合結構提供一個統一的接口。
實現:
Iterator:迭代器定義訪問和遍歷元素的接口。
ConcreteIterator:具體迭代器實現迭代器接口,對該聚合遍歷時跟蹤當前位置。
Aggregate:聚合定義創建相應迭代器對象接口。
ConcreteAggregate:具體聚合實現創建相應迭代器的接口,該操作返回ConcreteIterator的一個適當的實例。
ConcreteIterator跟蹤聚合中的當前對象,并能夠計算出待遍歷的后繼對象。

3.5中介者模式(mediator)
用一個中介對象來封裝一系列的對象交互。中介者使各對象不需要顯示地相互引用,從而使其耦合松散,而且可以獨立地改變它們之間的交互。
適用范圍:
1.一組對象以良好但是復雜的方式進行通信,產生的相互依賴關系結構混亂且難以理解。
2.一個對象引用其他很多對象并且直接與這些對象通信,導致難以復用該對象。
3.想定制一個分布在多個類中的行為,而又不想生成太多的子類。
實現:
Mediator:中介者定義一個接口用于與各Colleague對象通信。
ConcreteMediator:具體中介者通過協調各Colleague對象實現協作行為。了解并維護它的各個Colleague。
Colleague:每個Colleague類都知道它的中介者對象。每個Colleague對象在需與其他的Colleague通信時,與它的中介者通信。
Colleague向一個Mediator對象發送和接收請求,Mediator在各Colleague間適當地轉發請求以實現協作行為。

3.6備忘錄模式(memento)
在不破壞封裝性的前提下,捕獲一個對象的內部狀態,并在該對象之外保存這個狀態,這樣以后就可將該對象回復到原先保存的狀態。
適用范圍:
1.必須保存一個對象在某一個時刻的狀態,這樣以后需要時它才能恢復到先前的狀態。
2.如果一個用接口來讓其他對象直接得到這些狀態,將會暴露對象的實現細節并破壞對象的封裝性。
實現:
Memento:存儲Originator對象的內部狀態。防止Originator以外的其他對象訪問備忘錄。
Originator:創建一個Memento用以記錄當前時刻它的內部狀態。使用Memento恢復內部狀態。
Caretaker:負責保存好Memento。不能對Memento的內容進行操作或檢查。
Caretaker向Originator請求一個Memento,當需要時將其送回給Originator。

3.7觀察者模式(observer)
定義對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴于它的對象都得到通知并被自動更新。
適用范圍:
1.當一個抽象模型有兩個方面,其中一個方面依賴另一個方面。
2.當對一個對象的改變需要同時改變其它對象,而不知道具體有多少對象有待改變。
3.當一個對象必須通知其它對象,而它又不能假定其它對象是誰。換而言之,你不希望這些對象是緊耦合的。
實現:
Subject:目標制定它的觀察者。提供注冊和刪除觀察者對象的接口。
Observer:為那些在目標發生改變時需獲得通知的對象定義一個更新接口。
ConcreteSubject:將有關狀態存入各ConcreteObserver對象。當它的狀態發生改變時,向它的各個觀察者發出通知。
ConcreteObserver:維護一個指向ConcreteSubject對象的引用。存儲有關狀態。實現Observer的更新接口以使自身狀態與目標狀態保持一致。
當ConcreteSubject發生任何可能導致其觀察者與其本身狀態不一致的改變時,它將通知它的各個觀察者。在等到一個具體目標的改變通知后,ConcreteObserver對象可向目標對象查詢信息。ConcreteObserver使用這些信息以使它的狀態與目標對象的狀態一致。

3.8狀態模式(state)
允許一個對象在其內部狀態改變時改變它的行為。
適用范圍:
1.一個對象的行為取決于它的狀態,并且它必須在運行時刻根據狀態改變它的行為。
2.一個操作中含有龐大的多分支的條件語句,且這些分支依賴于該對象的狀態。
實現:
Context:定義用戶感興趣的接口。維護一個ConcreteState子類的實例,這個實例定義當前狀態。
State:定義一個接口以封裝與Context的一個特定狀態相關的行為。
ConcreteState subclasses:每一子類實現一個與Context的一個狀態相關的行為。
Context將與狀態相關的請求委托給當前的ConcreteState對象處理。Context可將自身作為一個參數傳遞給處理該請求的狀態對象,這使得狀態對象在必要時可以訪問Context。Context是客戶使用的主要接口。
Context包含一個State指針,用戶感興趣的接口實際調用State的操作。

3.9策略模式(strategy)
定義一系列的算法,把它們一個個封裝起來,并且使它們可相互替換。
適用范圍:
1.許多相關的類僅僅是因為行為有異。
2.需要使用一個算法的不同變體。
3.一個類定義了多種行為,并且這些行為在這個類的操作中以多個條件語句額形式出現。
實現:
Strategy:定義所有支持的算法的公共接口。
ConcreteStrategy:以Strategy接口實現某具體算法。
Context:用一個ConcreteStrategy對象來配置。維護一個對Strategy對象的引用。
Strategy和Context相互作用以實現選定的算法。Context將它的客戶的請求轉發給它的Strategy。
實際模式架構與狀態模式相同

3.10模板方法模式(template method)
定義一個操作中的算法的骨架,而將一些步驟的實現延遲到子類中。
適用范圍:
1.一次性實現一個算法的不變的部分,并將可變的行為留給子類來實現。
2.各子類中公共的行為應被提取出來并集中到一個公共父類中以避免代碼重復。
3.控制子類的擴展。
實現:
AbstractClass:定義抽象的原語操作,具體的子類將重定義它們以實現一個算法的各步驟。實現一個模板方法,定義一個算法的骨架。
ConcreteClass:實現原語操作以完成算法中與特定子類相關的步驟
ConcreteClass靠AbstractClass來實現算法中不變的步驟。
算法中變的部分為AbstractClass的虛函數,由子類ConcreteClass實現。

3.11訪問者模式(visitor)
表示一個作用于某對象結構中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用這些元素的新操作。
適用范圍:
1.一個對象結構包含很多類對象,它們有不同的接口,而你想對這些對象實施一些依賴于其具體類的操作。
2.需要對一個對象結構中的對象進行很多不同的并且不相關的操作,而你想避免讓這些操作“污染”這些對象類。
3.定義對象結構的類很少改變,但經常需要在此結構上定義新的操作。
實現:
Vistor:為該對象結構中的ConcreteElement的每一個類聲明一個Visit操作。
ConcreteVisitor:實現每個由Visitor聲明的操作。
Element:定義一個Accept操作,它以一個訪問者為參數。
ConcreteElement:實現Accept操作。
ObjectStructure:能枚舉它的元素。可以提供一個高層的接口以允許該訪問者訪問它的元素。
一個使用Visitor模式的客戶必須創建一個ConcreteVisitor對象,然后遍歷該對象結構,并用該訪問者訪問每一個元素。當一個元素被訪問時,它調用對應于它的類的Visitor操作。
Element定義一個Accept操作,它以一個Vistor為參數,在函數中調用Vistor的接口進行操作。

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

推薦閱讀更多精彩內容