主頁 > 軟體設計 > 設計模式學習筆記

設計模式學習筆記

2020-09-14 13:23:16 軟體設計

楊柳依 創建于2019年11月3日,最近更新于2019年11月8日

參考資料:大話設計模式 | 圖解設計模式 | 菜鳥教程—設計模式

UML類圖

UML類圖.jpg


【矩形框】代表一個類(Class),類圖分三層:

  • 第一層顯示類的名稱,如果是抽象類,則就用斜體顯示;

  • 第二層是類的特性,通常就是欄位和屬性;

  • 第三層是類的操作,通常是方法或行為,注意前面的符號,+表示public,-表示private,#表示 protected,


【線條】代表類之間的關系,

繼承:空心三角形+實線,鳥類繼承動物類

實作:空心三角形+虛線,鳥類實作飛翔介面

關聯:實線箭頭,企鵝類知道氣候類(企鵝類中參考了氣候物件)

聚合:空心菱形+實線箭頭,每只大雁都是屬于一個雁群,一個雁群可以有多只大雁(雁群中參考了大雁陣列物件)

組合:實心菱形+實線箭頭,翅膀是鳥的一部分,擁有相同的生命周期(初始化鳥物件時,同時實體化翅膀物件)

依賴:虛線箭頭,動物需要氧氣、水(氧氣和水是動物類某個方法的引數)

六大原則 + 一個法則

開放封閉原則:實作熱插拔,提高擴展性,

單一職責原則:一個類只負責一個職責,

里氏代換原則:實作抽象的規范,實作子父類互相替換,

依賴倒轉原則:針對介面編程,實作開閉原則的基礎,

介面隔離原則:降低耦合度,介面單獨設計,互相隔離,

合成復用原則:盡量使用聚合,組合,而不是繼承,

迪米特法則:功能模塊盡量獨立,

1. 開放封閉原則

開閉原則的意思是:對擴展開放,對修改關閉,軟體物體(類、模塊、函式等)應該可以擴展,但不可修改,即面對需求,對程式的改動是通過增加新代碼進行的,而不是更改現有的代碼,

以計算器程式為例,抽象出一個運算類,嗎,每當要增加新的運算方式時,只要修改這個抽象類和增加新的運算類,不會修改已有的運算類,

2. 單一職責原則

單一職責原則,就一個類而言,應該僅有一個引起它變化的原因,

以俄羅斯方塊為例,表單顯示(界面)是一個類,方塊的移動控制(游戲邏輯)是另一個類,將不同的職責分離到不同的類上,

3. 里氏代換原則

里氏替換原則:子型別必須能夠替換掉它們的父型別,(多型)

里氏代換原則是面向物件設計的基本原則之一, 里氏代換原則中說,任何基類可以出現的地方,子類一定可以出現,LSP 是繼承復用的基石,只有當派生類可以替換掉基類,且軟體單位的功能不受到影響時,基類才能真正被復用,而派生類也能夠在基類的基礎上增加新的行為,里氏代換原則是對開閉原則的補充,實作開閉原則的關鍵步驟就是抽象化,而基類與子類的繼承關系就是抽象化的具體實作,所以里氏代換原則是對實作抽象化的具體步驟的規范,

4. 依賴倒轉原則

也叫依賴倒置、依賴反轉,這個原則是開閉原則的基礎,

依賴倒轉原則,A)高層模塊不應該依賴低層模塊,兩個都應該依賴抽象;b)抽象不應該依賴細節,細節應該依賴抽象,即針對介面名稱,不要對實作編程,

例如,電腦可以很容易修理,因為電腦內部都是由一些(高內聚低耦合的)配件組成,壞了換一個新的就可;但是收音機很難修理,因為收音機里面都是一些元器件耦合在一起,

5. 介面隔離原則

這個原則的意思是:使用多個隔離的介面,比使用單個介面要好,它還有另外一個意思是:降低類之間的耦合度,由此可見,其實設計模式就是從大型軟體架構出發、便于升級和維護的軟體設計思想,它強調降低依賴,降低耦合,

6. 合成復用原則

合成復用原則是指:盡量使用合成/聚合的方式,而不是使用繼承,

7. 迪米特法則

又稱最少知道原則,是指:一個物體應當盡量少地與其他物體之間發生相互作用,使得系統功能模塊相對獨立,

如果兩個類不必彼此直接通信,那么這兩個類就不應當發生直接的相互作用,如果其中一個類需要呼叫另一個類的某一個方法,可以通過第三者轉發這個呼叫,

例如,公司小李去維修電腦,只需要去找IT部,讓IT部去找具體的人來維修電腦,

設計模式

1. 簡單工廠模式

不在 GoF23種設計模式中

傳入引數,由工廠物件去實體化實際的操作物件,

以計算器為例,傳入操作運算子(+-*/)給工廠物件,由工廠物件去創建實際的運算物件(為了便于擴展,這里不同的運算對應著不同的類,并且繼承著運算類),最后得到結果,

2. 策略模式

定義了演算法家族,分別封裝起來,讓它們之間可以互相替換,此模式讓演算法的變化,不會影響到使用演算法的客戶(多型),

以超市打折為例,正常收費,打折收費和返利收費是具體策略,用一個類去管理具體策略;同時還可以與簡單工廠模式結合,傳入演算法名稱,由工廠去創建策略管理類,

【優點】

  • 策略模式是一種定義一系列演算法的方法,從概念上來看,所有這些演算法完成的都是相同的作業,只是實作不同,它可以以相同的方式呼叫所有的演算法,減少了各種演算法類與使用演算法類之間的耦合,
  • 策略模式的Strategy類層次為Context定義了一系列的可供重用的演算法或行為,繼承有助于析取出這些演算法中的公共功能,
  • 公共的功能就是獲得計算費用的結果GetResult,這使得演算法間有了抽象的父類CashSuper,
  • 簡化了單元測驗,因為每個演算法都有自己的類,可以通過自己的介面單獨測驗

3. 裝飾器模式

裝飾器模式,動態地給一個物件添加一些額外的職責,就增加功能來說,裝飾器模式比生成子類更加靈活,它把每個要裝飾的功能放在單獨的類中,并讓這個類包裝它所要裝飾的物件,在使用時要注意裝飾的順序,

以穿衣服為例,人為一個抽象類,有穿衣這個抽象方法,具體的男人類繼承人抽象類,有一個抽象穿衣類(裝飾器類)繼承人抽象類,有具體的穿上衣類、穿外套類、穿內褲類、穿外褲類繼承抽象穿衣類,先創建一個男人物件X、穿上衣物件A、穿內褲物件B等,將X設定到A中,再將A設定到B中,鏈式呼叫(注意是一層套一層的),

4. 代理模式

代理模式,為其它物件提供一種代理以控制對這個物件的訪問,

例如,王小明通過戴勵給劉小紅送禮物,有

Subjec類:定義了RealSubject和Proxy的公用介面,這樣在任何使用RealSubject的地方都可以使用Proxy,【送禮物這一行為】

RealSubject類:定義Proxy所代表的真實物體,【王小明】

Proxy類:保存一個參考使得代理可以訪問真實物體,并提供一個與RealSubject內相同的訪問方法,這樣代理就可以用來替代真實物體,【戴勵】

5. 工廠方法模式

工廠模式方法,定義一個用于創建物件物件的介面,讓子類決定實體化哪一個類,工廠方法使一個類的實體化延遲到其子類,

以計算器程式為例,創建一個工廠介面,然后加減乘除各建一個具體的工廠去實作這個介面,每個具體工廠負責創建具體的運算物件,

6. 原型模式

原型模式,用原型實體指定創建物件的種類,并通過拷貝這些原型物件創建新的物件,

例如,有一個抽象原型類有抽象clone方法,然后有多個具體原型類去實作該clone方法,注意【淺拷貝與深拷貝】,原型中參考的物件,拷貝的時候只會拷貝參考,需要在參考的物件中也實作拷貝方法,然后在給原型賦值的是物件的拷貝,

7. 模板方法模式

定義一個操作中的演算法的骨架,將一些步驟延遲到子類中,模板方法使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟,

比如,一個抽象動物類有抽象吃食物的方法,在一些模板方法可以呼叫這個抽象方法(例如吃完東西才會睡覺),具體的狗類、貓類、鳥類實作具體的吃食物的方法,

8. 外觀模式

外觀模式,為子系統中的一組介面提供一個一致的界面,此模式定義了一個高層介面,這個介面使得這一子系統更加容易使用,

外觀模式完美的體現了依賴倒轉原則和迪米特法則的思想,

例如股民炒股,股民需要知道多個股票的情況,耦合性過高,而把錢投在基金上,由基金來管理多支股票,用戶只用與基金打交道,

【何時使用】

  1. 階段1:在設計初期,有意識的將不同層的業務分離,比如經典的MVC架構;
  2. 階段2:在開發階段,子系統會因為不斷的重構演化而變得越來越復雜,增加外觀Facade可以提供一個簡單的介面,減少它們之間的依賴;
  3. 階段3:對于維護遺留系統而言,可以為新系統開發一個外觀Facade類,讓新系統與Facade物件互動,Facade與遺留系統互動完成所有復雜的作業,

9. 建造者模式

建造者模式(Builder),又叫生成器模式,將一個復雜物件的構建與它的表示分離,使得同樣的構建程序可以創建不同的表示,

例如,一個畫小人程式,可以畫出瘦人、胖人等,有

Product類:小人類,由多個部分組成,

Builder介面:建造小人各個部分的抽象類,

ConcreteBuilder類:具體建造者,實作Builder介面,具體實作如何畫出小人的頭身手腳各個部分,

Director類:指揮者,構建一個使用Builder介面的物件,用來根據用戶的需求構建小人物件,

10. 觀察者模式

觀察者模式,又叫發布-訂閱(Publish/Subscribe)模式,定義了一種一對多的依賴關系,讓多個觀察者物件同時監聽某一個主題物件,這個主題物件在狀態發生變化時,會通知所有觀察者物件,使它們能夠自動更新自己,

例如,員工上班偷懶,需要前臺A或者前臺B望風,有

Subject類:抽象通知者類(主題),一般用一個抽象類或者一個介面實作,它把所有對觀察者物件的參考保存在一個聚集里,每個主題都可以有任何數量的觀察者,抽象主題提供一個介面,可以增加和洗掉觀察者物件,

Observer類:抽象觀察者,為所有的具體觀察者定義一個介面,在得到主題的通知時更新自己,這個介面叫做更新介面,抽象觀察者一般用一個抽象類或者一個介面實作,更新介面通常包含一個Update() 方法,這個方法叫做更新方法,

ConcreteSubject類:叫做具體主題或具體通知者,將有關狀態存入具體現察者物件;在具體主題的內部狀態改變時,給所有登記過的觀察者發出通知,具體主題角色通常用一個具體子類實作,

ConcreteObserver類:具體觀察者,實作抽象觀察者角色所要求的更新介面,以便使本身的狀態與主題的狀態相協調,具體觀察者角色可以保存一個指向具體主題物件的參考,具體觀察者角色通常用一個具體子類實作,

觀察者模式的關鍵物件是主題Subject和觀察者Observer,一個Subject可以有任意數目的依賴它的Observer,一旦Subject的狀態發生了改變,所有的Observer都可以得到通知,

觀察者模式所做的作業其實就是在解除耦合,讓耦合的雙方都依賴于抽象,而不是依賴于具體,從而使得各自的變化都不會影響另一邊的變化,

11. 抽象工廠模式

抽象工廠模式(Abstract Factory),提供一個創建一系列相關或相互依賴物件的介面,而無需指定它們具體的類,解決涉及到多個產品系列的問題,有一個專門的工廠模式叫抽象工廠模式,

例如,有一個業務需要訪問指定的資料庫(可能會變動),資料庫中又有幾張表,為了便于修改資料庫訪問方式,這時就需要使用抽象工廠模式,

抽象工廠介面:里面應該包含所有的產品創建的抽象方法【創建資料庫的抽象方法】;

具體的工廠:實作抽象工廠介面,創建具有特定實作的產品物件【實體化對應的具體資料庫物件】;

抽象產品:它們都有可能有多種不同的實作【資料庫的訪問資源方式的抽象方法】;

具體產品:繼承抽象產品,對抽象產品的具體分類的實作【具體資料庫的訪問資源方法】,


【改進1】反射

Java反射:通過全限定類名去加載對應類的位元組碼(Class)檔案

Class c =  Class.forName("com.loveshes.designpattern.reflect.User");
Constructor con = c.getConstructor(String.class, int.class);
User user = (User) con.newInstance("王飽飽", 20);

反射中的類名是字串,可以采用變數,故更容易修改為不同的資料庫具體產品,且不用在主程式中寫switch方法,

使用DataAccess類,用反射技術,取代IFactory、SqlserverFactory和AccessFactory,

【改進2】反射 + 組態檔

將資料庫名稱放在組態檔中,這樣只需要修改組態檔就可以修改程式的訪問資料庫,不用去改程式代碼,


【總結】從這個角度上說,所有在用簡單工廠的地方,都可以考慮用反射技術來去除switch或if,解除分支判斷帶來的耦合

12. 狀態模式

狀態模式(State),當一個物件的內在狀態改變時允許改變其行為,這個物件看起來像是改變了其類,

狀態模式主要解決的是當控制一個物件狀態轉換的條件運算式過于復雜時的情況,把狀態的判斷邏輯轉移到表示不同狀態的一系列類當中,可以把復雜的判斷邏輯簡化,

比如,上班時不同時間做不同作業就可以使用狀態模式,首先有一個抽象狀態類,設定多個作業狀態繼承抽象狀態類,有一個作業類(背景關系)來負責轉換作業轉態,傳入任意一個作業狀態,當滿足某條件的時候,轉入下一作業狀態,

13. 配接器模式

配接器模式(Adapter),將一個類的介面轉換成客戶希望的另外一個介面,Adapter模式使得原本由于介面不兼容而不能一起作業的那些類可以一起作業,

配接器模式有兩種型別,類配接器模式和物件配接器模式,類配接器通過多重繼承對一個介面與另一個介面進行匹配,物件配接器模式主要結構如下:

Target:客戶期待的介面

Adaptee:需要適配的類

Adapter:實作Target介面,通過在內部包裝一個Adaptee物件,把源介面轉換成目標介面

14. 備忘錄模式

備忘錄(Memento):在不破壞封裝性的前提下,捕獲一個物件的內部狀態,并在該物件之外保存這個狀態,這樣以后就可將該物件恢復到原先保存的狀態,

例如,有一個游戲角色,可以在戰斗之前保存狀態,戰斗失敗了可以恢復到之前保存的狀態,有

Originator類:發起人(游戲角色),負責創建一個備忘錄Memento,用以記錄當前時刻它的內部狀態,并可使用備忘錄恢復內部狀態,Originator 可根據需要決定Memento存盤Originator的哪些內部狀態,

Memento類:備忘錄(角色狀態),負責存盤Originator物件的內部狀態,并可防止Originator 以外的其他物件訪問備忘錄Memento,備忘錄有兩個介面,Caretaker只能看到備忘錄的窄介面,它只能將備忘錄傳遞給其他物件,Originator能夠看到一個寬介面,允許它訪問回傳到先前狀態所需的所有資料,

Caretaker類:管理者(負責管理狀態),負責保存好備忘錄Memento(Originator創建的備忘錄存在Caretaker里面),不能對備忘錄的內容進行操作或檢查,

Memento模式比較適用于功能比較復雜的,但需要維護或記錄屬性歷史的類,或者需要保存的屬性只是眾多屬性中的一小部分時,Originator可以根據保存的Memento資訊還原到前一狀態,

當角色的狀態改變的時候,有可能這個狀態無效,這時候就可以使用暫時存盤起來的備忘錄將狀態復原,

15. 組合模式

組合模式(Composite),將物件組合成樹形結構以表示部分-整體的層次結構,組合模式使得用戶對單個物件和組合物件的使用具有一致性,

比如,一個總公司有財務部、技術部、人力資源部等,還有分公司,分公司同樣有財務部、技術部、人力資源部等,可以先設計一個公司的抽象類(或者介面),里面有增加、移除、顯示部門、履行職責的抽象方法,然后設計具體的公司類繼承該抽象類,實作這些方法,并加上children相關的方法;部門類也去繼承公司抽象類,實作這些方法,創建分公司的時候同創建總公司相同,

這樣,基本物件可以被組合為更復雜的組合物件,這個組合物件又可以被組合,

16. 迭代器模式

迭代器模式(Iterator),提供一種方法順序訪問一個聚合物件中各個元素,而又不暴露該物件的內部表示,

當你需要訪問一個聚集物件,而且不管這些物件是什么都需要遍歷的時候,你就應該考慮用迭代器模式,當你需要對聚集有多種方式遍歷時,可以考慮用迭代器模式,Java中的for-each就是迭代器模式,

迭代器模式就是分離了集合物件的遍歷行為,抽象出一個選代器類來負責,這樣既可以做到不暴露集合的內部結構,又可讓外部代碼透明地訪問集合內部的資料,迭代器模式在訪問陣列、集合、串列等資料時,尤其是資料庫資料操作時,是非常普遍的應用,但由于它太普遍了,所以各種高級語言都對它進行了封裝,

17. 單例模式

單例模式(Singleton),保證一個類僅有一個實體,并提供一個訪問它的全域訪問點,

讓類自身負責保存它的唯一實體,這個類可以保證沒有其他實體可以被創建,并且它可以提供一個訪問該實體的方法(靜態方法),

單例模式有多種實作方法,參考單例模式 | 菜鳥教程

一般采用餓漢式在類直接創建靜態物件:

public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
    return instance;  
    }  
}

如果明確需要使用懶加載,可以采用登記式/靜態內部類方式:

public class Singleton {  
    private static class SingletonHolder {  
    	private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}
    public static final Singleton getInstance() {  
    	return SingletonHolder.INSTANCE;  
    }  
}

否則使用雙檢鎖/雙重校驗鎖方式:

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
        if (singleton == null) {  
            synchronized (Singleton.class) {  
                if (singleton == null) {  
                    singleton = new Singleton();  
                }  
            }  
    	}  
    	return singleton;  
    }  
}

18. 橋接模式

橋接模式(Bridge),將抽象部分與它的實作部分分離,使它們都可以獨立地變化,(實作指的是抽象類和它的派生類用來實作自己的物件),

實作系統可能有多角度分類,每一種分類都有可能變化,那么就把這種多角度分離出來讓它們獨立變化,減少它們之間的耦合,

例如為不同的手機開發游戲,可以將手機硬體和軟體分離,手機有A、B兩個品牌,軟體有M、N兩類,有一個抽象手機類,A手機、B手機繼承抽象手機類;有一個抽象軟體類,M軟體、N軟體繼承抽象軟體類;然后抽象手機類參考抽象軟體類,這樣不管增加手機還是增加軟體都很方便,

合成/聚合復用原則(CARP):盡量使用合成(組合) / 聚合,盡量不要使用類繼承,

19. 命令模式

命令模式(Command),將一個請求封裝為一個物件,從而使你可用不同的請求對客戶進行引數化;對請求排隊或記錄請求日志,以及支持可撤銷的操作,

例如點燒烤,我們是客戶端,服務員是Invoker,向廚師Receiver發送命令,其中有一個抽象的Command類用于宣告執行操作的介面,ConcreteCommand類繼承Command類,(系結接收者廚師Receiver)用于實作具體的動作,服務員Invoke是通過Command類來向廚師Receiver進行互動的,

【優點】

  • 能較容易地設計一個命令佇列;
  • 需要的情況下,可以較容易地將命令記入日志;
  • 允許接收請求的一方決定是否要否決請求,
  • 可以容易地實作對請求的撤銷和重做;
  • 由于加進新的具體命令類不影響其他的類,因此增加新的具體命令類很容易;
  • 命令模式把請求一個操作的物件(服務員)與知道怎么執行一個操作的物件(廚師)分割開,

敏捷開發原則告訴我們,不要為代碼添加基于猜測的、實際不需要的功能,

如果不清楚一個系統是否需要命令模式,一般就不要著急去實作它,事實上,在需要的時候通過重構實作這個模式并不困難,只有在真正需要如撤銷/恢復操作等功能時,把原來的代碼重構為命令模式才有意義,

20. 職責鏈模式

職責鏈模式(Chain of Responsibility),使多個物件都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關系,將這個物件連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個物件處理它為止,

比如,員工請假,不同管理者級別能處理的請假天數不一樣,設定一個管理者抽象類,有設定上級(繼任者)方法和處理請求的抽象方法,有多個級別的管理者繼承該抽象類,實作處理請求的抽象方法,這樣,員工(客戶端)每次都是向組長請假,組長批不了的就交由部門經理處理,經理處理不了的就由總監處理,

21. 中介者模式

中介者模式(Mediator),用一個中介物件來封裝一系列的物件互動,中介者使各物件不需要顯式地相互參考,從而使其耦合松散,而且可以獨立地改變它們之間的互動,

例如,聯合國安理會調節國家沖突,有一個聯合國抽象類,里面有調節抽象方法(引數為調節資訊和調節物件),有具體的安理會繼承聯合國抽象類,實作具體方法;有國家抽象類,需要設定中介者,有具體國家類繼承國家抽象類,實作具體方法;在實際使用時,由中介者去呼叫國家類的方法,

中介者模式一般應用于一組物件以定義良好但是復雜的方式進行通信的場合,比如剛才得到的表單Form物件或Web頁面aspx,以及想定制一個分布在多個類中的行為,而又不想生成太多的子類的場合,

【優點】

  • Mediator的出現減少了各個Colleague的耦合,便得可以獨立地改變和復用各個Colleague類和Mediator,

  • 由于把物件如何協作進行了抽象,將中介作為一個獨立的概念并將其封裝在一個物件中,這樣關注的物件就從物件各自本身的行為轉移到它們之間的互動上來,也就是站在一個更宏觀的角度去看待系統,

【缺點】

  • 由于ConcreteMediator 控制了集中化,于是就把互動復雜性變為了中介者的復雜性,這就使得中介者會變得比任何一個ConcreteColleague都復雜,

22. 享元模式

享元模式(Flyweight),運用共享技術有效地支持大量細粒度的物件,

比如為不同人創建類似的網站,可以把網站的公共部分抽取出來,將用戶設定為外部狀態傳進去,這樣的話,就算要為10個用戶創建網站,也可以只有一個網站實體,有用戶類,有一個抽象網站類,里面有抽象使用方法(傳入用戶),有多個具體的網站類,實作抽象方法;有一個網站工廠負責管理網站(沒有則創建,有則取出回傳),

如果一個應用程式使用了大量的物件,而大量的這些物件造成了很大的存盤開銷時就應該考慮使用;還有就是物件的大多數狀態可以外部狀態,如果洗掉物件的外部狀態,那么可以用相對較少的共享物件取代很多組物件,此時可以考慮使用享元模式,

【優點】

  • 享元模式的優點在于它可以極大減少記憶體中物件的數量,使得相同物件或相似物件在記憶體中只保存一份,
  • 享元模式的外部狀態相對獨立,而且不會影響其內部狀態,從而使得享元物件可以在不同的環境中被共享,

【缺點】

  • 享元模式使得系統更加復雜,需要分離出內部狀態和外部狀態,這使得程式的邏輯復雜化,
  • 為了使物件可以共享,享元模式需要將享元物件的狀態外部化,而讀取外部狀態使得運行時間變長

Java中的字串(會放到字串池中)就是用了享元模式,

23. 解釋器模式

解釋器模式(interpreter),給定一個語言,定義它的文法的一種表示,并定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子,

比如正則運算式,可以用特定的文法去匹配字串,

AbstractExpression類:抽象運算式,宣告一個抽象的解釋操作,這個介面為抽象語法樹中所有的節點所共享,

TerminalExpression類:終結符運算式,實作與文法中的終結符相關聯的解釋操作,實作抽象運算式中所要求的介面,主要是一個interpret() 方法,文法中每一個終結符都有一個具體終結運算式與之相對應,

NonterminalExpression類:非終結符運算式,為文法中的非終結符實作解釋操作,對文法中每一條規則 R1、R2……Rn 都需要一個具體的非終結符運算式類,通過實作抽象運算式的interpret() 方法實作解釋操作,解釋操作以遞回方式呼叫上面所提到的代表R1、R2……Rn中各個符號的實體變數,

Context類:包含解釋器之外的一些全域資訊,

24. 訪問者模式

訪問者模式(Visitor),表示一個作用于某物件結構中的各元素的操作,它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作,

比如,有男人、女人2種資料結構,每類人都有多個情緒,情緒對應的操作不同,有抽象訪問者類Visitor,為該物件結構中ConcreteElement的每一個類宣告一個Visit操作;ConcreteVisitor1和ConcreteVisitor2類,具體訪問者,實作每個由Visitor宣告的操作;人抽象類Element,定義一個Accept操作,它以一個訪問者為引數;男人類 ConcreteElementA和女人類ConcreteElementB,具體元素,實作Accept操作;人的集合ObjectStructure類,能列舉它的元素,可以提供一個高層的介面以允許訪問者訪問它的元素,

Accept操作充分利用雙分派技術,實作處理與資料結構的分離,

在客戶程式中將具體狀態作為引數傳遞給男人類完成了一次分派,然后男人類呼叫作為引數的具體狀態中的方法男人反應,同時將自己(this)作為引數傳遞進去,這便完成了第二次分派,雙分派意味著得到執行的操作決定于請求的種類和兩個接收者的型別,接受方法就是一個雙分派的操作,它得到執行的操作不僅決定于狀態類的具體狀態,還決定于它訪問的人的類別

訪問者模式適用于資料結構相對穩定的系統,它把資料結構和作用于結構上的操作之間的耦合解脫開,使得操作集合可以相對自由地演化,

【優點】

  • 增加新的操作很容易,因為增加新的操作就意味著增加一個新的訪問者,訪問者模式將有關的行為集中到一個訪問者物件中,

【缺點】

  • 增加新的資料結構變得困難,

訪問者模式的目的是要把處理從資料結構分離出來,很多系統可以按照演算法和資料結構分開,如果這樣的系統有比較穩定的資料結構,又有易于變化的演算法的話,使用訪問者模式就是比較合適的,因為訪問者模式使得演算法操作的增加變得容易,反之,如果這樣的系統的資料結構物件易于變化,經常要有新的資料物件增加進來,就不適合使用訪問者模式,

設計模式總結[23種]

1. 創建型模式

創建型模式 --> 物件怎么來

抽象工廠模式:提供一個創建一系列或相關依賴物件的介面,而無需指定它們具體的類,

建造者模式:將一個復雜物件的構建與它的表示分離,使得同樣的構建程序可以創建不同的表示,

工廠方法模式:定義一個用于創建物件的介面,讓子類決定實體化哪一個類,工廠模式使一個類的實體化延遲到其子類,

原型模式:用原型實體指定創建物件的種類,并且通過拷貝這些原型創建新的物件,

單例模式:保證一個類僅有一個實體,并提供一個訪問它的全域訪問點,

創建型模式隱藏了這些類的實體是如何被創建和放在一起,整個系統關于這些物件所知道的是由抽象類所定義的介面,這樣,創建型模式在創建了什么、誰創建它、它是怎么被創建的,以及何時創建這些方面提供了很大的靈活性,

2. 結構型模式

結構型模式 --> 物件和誰有關

配接器模式:將一個類的介面轉換成客戶希望的另外一個介面,配接器模式使得原本由于介面不兼容而不能一起作業的那些類可以一起作業,

橋接模式:將抽象部分與它的實作部分分離,使它們都可以獨立地變化,

組合模式:將物件組合成樹形結構以表示“部分-整體”的層次結構,組合模式使得用戶對單個物件和組合物件的使用具有一致性,

裝飾器模式:動態地給一個物件添加一些額外的職責,就增加功能來說,裝飾模式相比生成子類更加靈活,

外觀模式:為子系統中的一組介面提供一個一致的界面,外觀模式定義了一個高層介面,這個介面使得這一子系統更加容易使用,

享元模式:運用共享技術有效地支持大量細粒度的物件,

代理模式:為其他物件提供一種代理以控制對這個物件的訪問,

3. 行為型模式

行為型模式 --> 物件與物件在干嘛

觀察者模式:定義物件間的一種一對多的依賴關系,當一個物件的狀態發生改變時,所有依賴于它的物件都得到通知并被自動更新,

模板方法模式:定義一個操作的演算法骨架,而將一些步驟延遲到子類中,模板方法使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟,

命令模式:將一個請求封裝為一個物件,從而使你可用不同的請求對客戶進行引數化;可以對請求排隊或記錄請求日志,以及支持可撤銷的操作,

狀態模式:允許一個物件在其內部狀態改變時改變它的行為,讓物件看起來似乎修改了它的類,

職責鏈模式:多個物件都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關系,將這些物件連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個物件處理它為止,

解釋器模式:給定一個語言,定義它的文法的一種表示,并定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子,

中介者模式:一個中介物件來封裝一系列的物件互動,中介者使各對像不需要顯式地相互參考,從而使其耦合松散,而且可以獨立地改變它們之間的互動,

訪問者模式:表示一個作用于某物件結構中的各元素的操作,它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作,

策略模式:定義一系列的演算法,把它們一個個封裝起來,并且使它們可相互替換,使得演算法可獨立于使用它的客戶而變化,

備忘錄模式:在不破壞封裝性的前提下,捕獲一個物件的內部狀態,并在該物件之外保存這個狀態,這樣以后就可將該物件恢復到原先保存的狀態,

迭代器模式:提供一種方法順序訪問一個聚合物件中各個元素,而又不需暴露該物件的內部表示,

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/35312.html

標籤:設計模式

上一篇:設計模式系列之二:23種GoF設計模式的分類

下一篇:設計模式系列之一:23種GoF設計模式概述

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more