由 楊柳依 創(chuàng)建于2019年11月3日,最近更新于2019年11月8日
【矩形框】代表一個類(Class)。類圖分三層:
第一層顯示類的名稱,如果是抽象類,則就用斜體顯示;
第二層是類的特性,通常就是字段和屬性;
第三層是類的操作,通常是方法或行為。注意前面的符號,+
表示public,-
表示private,#
表示 protected。
【線條】代表類之間的關系。
繼承:空心三角形+實線,鳥類繼承動物類
實現(xiàn):空心三角形+虛線,鳥類實現(xiàn)飛翔接口
關聯(lián):實線箭頭,企鵝類知道氣候類(企鵝類中引用了氣候對象)
聚合:空心菱形+實線箭頭,每只大雁都是屬于一個雁群,一個雁群可以有多只大雁(雁群中引用了大雁數(shù)組對象)
組合:實心菱形+實線箭頭,翅膀是鳥的一部分,擁有相同的生命周期(初始化鳥對象時,同時實例化翅膀對象)
依賴:虛線箭頭,動物需要氧氣、水(氧氣和水是動物類某個方法的參數(shù))
開放封閉原則:實現(xiàn)熱插拔,提高擴展性。
單一職責原則:一個類只負責一個職責。
里氏代換原則:實現(xiàn)抽象的規(guī)范,實現(xiàn)子父類互相替換。
依賴倒轉原則:針對接口編程,實現(xiàn)開閉原則的基礎。
接口隔離原則:降低耦合度,接口單獨設計,互相隔離。
合成復用原則:盡量使用聚合,組合,而不是繼承。
迪米特法則:功能模塊盡量獨立。
開閉原則的意思是:對擴展開放,對修改關閉。軟件實體(類、模塊、函數(shù)等)應該可以擴展,但不可修改。即面對需求,對程序的改動是通過增加新代碼進行的,而不是更改現(xiàn)有的代碼。
以計算器程序為例,抽象出一個運算類,嗎,每當要增加新的運算方式時,只要修改這個抽象類和增加新的運算類,不會修改已有的運算類。
單一職責原則,就一個類而言,應該僅有一個引起它變化的原因。
以俄羅斯方塊為例,窗體顯示(界面)是一個類,方塊的移動控制(游戲邏輯)是另一個類,將不同的職責分離到不同的類上。
里氏替換原則:子類型必須能夠替換掉它們的父類型。(多態(tài))
里氏代換原則是面向對象設計的基本原則之一。 里氏代換原則中說,任何基類可以出現(xiàn)的地方,子類一定可以出現(xiàn)。LSP 是繼承復用的基石,只有當派生類可以替換掉基類,且軟件單位的功能不受到影響時,基類才能真正被復用,而派生類也能夠在基類的基礎上增加新的行為。里氏代換原則是對開閉原則的補充。實現(xiàn)開閉原則的關鍵步驟就是抽象化,而基類與子類的繼承關系就是抽象化的具體實現(xiàn),所以里氏代換原則是對實現(xiàn)抽象化的具體步驟的規(guī)范。
也叫依賴倒置、依賴反轉。這個原則是開閉原則的基礎。
依賴倒轉原則,A)高層模塊不應該依賴低層模塊,兩個都應該依賴抽象;b)抽象不應該依賴細節(jié),細節(jié)應該依賴抽象。即針對接口名稱,不要對實現(xiàn)編程。
例如,電腦可以很容易修理,因為電腦內部都是由一些(高內聚低耦合的)配件組成,壞了換一個新的就可;但是收音機很難修理,因為收音機里面都是一些元器件耦合在一起。
這個原則的意思是:使用多個隔離的接口,比使用單個接口要好。它還有另外一個意思是:降低類之間的耦合度。由此可見,其實設計模式就是從大型軟件架構出發(fā)、便于升級和維護的軟件設計思想,它強調降低依賴,降低耦合。
合成復用原則是指:盡量使用合成/聚合的方式,而不是使用繼承。
又稱最少知道原則,是指:一個實體應當盡量少地與其他實體之間發(fā)生相互作用,使得系統(tǒng)功能模塊相對獨立。
如果兩個類不必彼此直接通信,那么這兩個類就不應當發(fā)生直接的相互作用。如果其中一個類需要調用另一個類的某一個方法,可以通過第三者轉發(fā)這個調用。
例如,公司小李去維修電腦,只需要去找IT部,讓IT部去找具體的人來維修電腦。
不在 GoF23種設計模式中
傳入?yún)?shù),由工廠對象去實例化實際的操作對象。
以計算器為例,傳入操作運算符(+
、-
、*
、/
)給工廠對象,由工廠對象去創(chuàng)建實際的運算對象(為了便于擴展,這里不同的運算對應著不同的類,并且繼承著運算類),最后得到結果。
定義了算法家族,分別封裝起來,讓它們之間可以互相替換,此模式讓算法的變化,不會影響到使用算法的客戶(多態(tài))。
以超市打折為例,正常收費,打折收費和返利收費是具體策略,用一個類去管理具體策略;同時還可以與簡單工廠模式結合,傳入算法名稱,由工廠去創(chuàng)建策略管理類。
【優(yōu)點】
裝飾器模式,動態(tài)地給一個對象添加一些額外的職責,就增加功能來說,裝飾器模式比生成子類更加靈活。它把每個要裝飾的功能放在單獨的類中,并讓這個類包裝它所要裝飾的對象,在使用時要注意裝飾的順序。
以穿衣服為例,人為一個抽象類,有穿衣這個抽象方法,具體的男人類繼承人抽象類,有一個抽象穿衣類(裝飾器類)繼承人抽象類,有具體的穿上衣類、穿外套類、穿內褲類、穿外褲類繼承抽象穿衣類。先創(chuàng)建一個男人對象X、穿上衣對象A、穿內褲對象B等,將X設置到A中,再將A設置到B中,鏈式調用(注意是一層套一層的)。
代理模式,為其它對象提供一種代理以控制對這個對象的訪問。
例如,王小明通過戴勵給劉小紅送禮物,有
Subjec類:定義了RealSubject和Proxy的公用接口,這樣在任何使用RealSubject的地方都可以使用Proxy?!舅投Y物這一行為】
RealSubject類:定義Proxy所代表的真實實體?!就跣∶鳌?/p>
Proxy類:保存一個引用使得代理可以訪問真實實體,并提供一個與RealSubject內相同的訪問方法,這樣代理就可以用來替代真實實體?!敬鲃睢?/p>
工廠模式方法,定義一個用于創(chuàng)建對象對象的接口,讓子類決定實例化哪一個類,工廠方法使一個類的實例化延遲到其子類。
以計算器程序為例,創(chuàng)建一個工廠接口,然后加減乘除各建一個具體的工廠去實現(xiàn)這個接口,每個具體工廠負責創(chuàng)建具體的運算對象。
原型模式,用原型實例指定創(chuàng)建對象的種類,并通過拷貝這些原型對象創(chuàng)建新的對象。
例如,有一個抽象原型類有抽象clone方法,然后有多個具體原型類去實現(xiàn)該clone方法,注意【淺拷貝與深拷貝】,原型中引用的對象,拷貝的時候只會拷貝引用,需要在引用的對象中也實現(xiàn)拷貝方法,然后在給原型賦值的是對象的拷貝。
定義一個操作中的算法的骨架,將一些步驟延遲到子類中。模板方法使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。
比如,一個抽象動物類有抽象吃食物的方法,在一些模板方法可以調用這個抽象方法(例如吃完東西才會睡覺),具體的狗類、貓類、鳥類實現(xiàn)具體的吃食物的方法。
外觀模式,為子系統(tǒng)中的一組接口提供一個一致的界面,此模式定義了一個高層接口,這個接口使得這一子系統(tǒng)更加容易使用。
外觀模式完美的體現(xiàn)了依賴倒轉原則和迪米特法則的思想。
例如股民炒股,股民需要知道多個股票的情況,耦合性過高,而把錢投在基金上,由基金來管理多支股票,用戶只用與基金打交道。
【何時使用】
建造者模式(Builder),又叫生成器模式,將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創(chuàng)建不同的表示。
例如,一個畫小人程序,可以畫出瘦人、胖人等,有
Product類:小人類,由多個部分組成。
Builder接口:建造小人各個部分的抽象類。
ConcreteBuilder類:具體建造者,實現(xiàn)Builder接口。具體實現(xiàn)如何畫出小人的頭身手腳各個部分。
Director類:指揮者,構建一個使用Builder接口的對象。用來根據(jù)用戶的需求構建小人對象。
觀察者模式,又叫發(fā)布-訂閱(Publish/Subscribe)模式,定義了一種一對多的依賴關系,讓多個觀察者對象同時監(jiān)聽某一個主題對象。這個主題對象在狀態(tài)發(fā)生變化時,會通知所有觀察者對象,使它們能夠自動更新自己。
例如,員工上班偷懶,需要前臺A或者前臺B望風,有
Subject類:抽象通知者類(主題)。一般用一個抽象類或者一個接口實現(xiàn)。它把所有對觀察者對象的引用保存在一個聚集里,每個主題都可以有任何數(shù)量的觀察者。抽象主題提供一個接口,可以增加和刪除觀察者對象。
Observer類:抽象觀察者,為所有的具體觀察者定義一個接口,在得到主題的通知時更新自己。這個接口叫做更新接口。抽象觀察者一般用一個抽象類或者一個接口實現(xiàn)。更新接口通常包含一個Update() 方法,這個方法叫做更新方法。
ConcreteSubject類:叫做具體主題或具體通知者,將有關狀態(tài)存入具體現(xiàn)察者對象;在具體主題的內部狀態(tài)改變時,給所有登記過的觀察者發(fā)出通知。具體主題角色通常用一個具體子類實現(xiàn)。
ConcreteObserver類:具體觀察者,實現(xiàn)抽象觀察者角色所要求的更新接口,以便使本身的狀態(tài)與主題的狀態(tài)相協(xié)調。具體觀察者角色可以保存一個指向具體主題對象的引用。具體觀察者角色通常用一個具體子類實現(xiàn)。
觀察者模式的關鍵對象是主題Subject和觀察者Observer,一個Subject可以有任意數(shù)目的依賴它的Observer,一旦Subject的狀態(tài)發(fā)生了改變,所有的Observer都可以得到通知。
觀察者模式所做的工作其實就是在解除耦合。讓耦合的雙方都依賴于抽象,而不是依賴于具體。從而使得各自的變化都不會影響另一邊的變化。
抽象工廠模式(Abstract Factory),提供一個創(chuàng)建一系列相關或相互依賴對象的接口,而無需指定它們具體的類。解決涉及到多個產(chǎn)品系列的問題,有一個專門的工廠模式叫抽象工廠模式。
例如,有一個業(yè)務需要訪問指定的數(shù)據(jù)庫(可能會變動),數(shù)據(jù)庫中又有幾張表,為了便于修改數(shù)據(jù)庫訪問方式,這時就需要使用抽象工廠模式。
抽象工廠接口:里面應該包含所有的產(chǎn)品創(chuàng)建的抽象方法【創(chuàng)建數(shù)據(jù)庫的抽象方法】;
具體的工廠:實現(xiàn)抽象工廠接口,創(chuàng)建具有特定實現(xiàn)的產(chǎn)品對象【實例化對應的具體數(shù)據(jù)庫對象】;
抽象產(chǎn)品:它們都有可能有多種不同的實現(xiàn)【數(shù)據(jù)庫的訪問資源方式的抽象方法】;
具體產(chǎn)品:繼承抽象產(chǎn)品,對抽象產(chǎn)品的具體分類的實現(xiàn)【具體數(shù)據(jù)庫的訪問資源方法】。
【改進1】反射
Java反射:通過全限定類名去加載對應類的字節(jié)碼(Class)文件
Class c = Class.forName("com.loveshes.designpattern.reflect.User");Constructor con = c.getConstructor(String.class, int.class);User user = (User) con.newInstance("王飽飽", 20);
反射中的類名是字符串,可以采用變量,故更容易修改為不同的數(shù)據(jù)庫具體產(chǎn)品,且不用在主程序中寫switch方法。
使用DataAccess類,用反射技術,取代IFactory、SqlserverFactory和AccessFactory。
【改進2】反射 + 配置文件
將數(shù)據(jù)庫名稱放在配置文件中,這樣只需要修改配置文件就可以修改程序的訪問數(shù)據(jù)庫,不用去改程序代碼。
【總結】從這個角度上說,所有在用簡單工廠的地方,都可以考慮用反射技術來去除switch或if,解除分支判斷帶來的耦合。
狀態(tài)模式(State),當一個對象的內在狀態(tài)改變時允許改變其行為,這個對象看起來像是改變了其類。
狀態(tài)模式主要解決的是當控制一個對象狀態(tài)轉換的條件表達式過于復雜時的情況。把狀態(tài)的判斷邏輯轉移到表示不同狀態(tài)的一系列類當中,可以把復雜的判斷邏輯簡化。
比如,上班時不同時間做不同工作就可以使用狀態(tài)模式,首先有一個抽象狀態(tài)類,設置多個工作狀態(tài)繼承抽象狀態(tài)類,有一個工作類(上下文)來負責轉換工作轉態(tài),傳入任意一個工作狀態(tài),當滿足某條件的時候,轉入下一工作狀態(tài)。
適配器模式(Adapter),將一個類的接口轉換成客戶希望的另外一個接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。
適配器模式有兩種類型,類適配器模式和對象適配器模式。類適配器通過多重繼承對一個接口與另一個接口進行匹配。對象適配器模式主要結構如下:
Target:客戶期待的接口
Adaptee:需要適配的類
Adapter:實現(xiàn)Target接口,通過在內部包裝一個Adaptee對象,把源接口轉換成目標接口
備忘錄(Memento):在不破壞封裝性的前提下,捕獲一個對象的內部狀態(tài),并在該對象之外保存這個狀態(tài)。這樣以后就可將該對象恢復到原先保存的狀態(tài)。
例如,有一個游戲角色,可以在戰(zhàn)斗之前保存狀態(tài),戰(zhàn)斗失敗了可以恢復到之前保存的狀態(tài)。有
Originator類:發(fā)起人(游戲角色)。負責創(chuàng)建一個備忘錄Memento,用以記錄當前時刻它的內部狀態(tài),并可使用備忘錄恢復內部狀態(tài)。Originator 可根據(jù)需要決定Memento存儲Originator的哪些內部狀態(tài)。
Memento類:備忘錄(角色狀態(tài))。負責存儲Originator對象的內部狀態(tài),并可防止Originator 以外的其他對象訪問備忘錄Memento。備忘錄有兩個接口,Caretaker只能看到備忘錄的窄接口,它只能將備忘錄傳遞給其他對象。Originator能夠看到一個寬接口,允許它訪問返回到先前狀態(tài)所需的所有數(shù)據(jù)。
Caretaker類:管理者(負責管理狀態(tài))。負責保存好備忘錄Memento(Originator創(chuàng)建的備忘錄存在Caretaker里面),不能對備忘錄的內容進行操作或檢查。
Memento模式比較適用于功能比較復雜的,但需要維護或記錄屬性歷史的類,或者需要保存的屬性只是眾多屬性中的一小部分時,Originator可以根據(jù)保存的Memento信息還原到前一狀態(tài)。
當角色的狀態(tài)改變的時候,有可能這個狀態(tài)無效,這時候就可以使用暫時存儲起來的備忘錄將狀態(tài)復原。
組合模式(Composite),將對象組合成樹形結構以表示部分-整體的層次結構。組合模式使得用戶對單個對象和組合對象的使用具有一致性。
比如,一個總公司有財務部、技術部、人力資源部等,還有分公司,分公司同樣有財務部、技術部、人力資源部等??梢韵仍O計一個公司的抽象類(或者接口),里面有增加、移除、顯示部門、履行職責的抽象方法,然后設計具體的公司類繼承該抽象類,實現(xiàn)這些方法,并加上children相關的方法;部門類也去繼承公司抽象類,實現(xiàn)這些方法。創(chuàng)建分公司的時候同創(chuàng)建總公司相同。
這樣,基本對象可以被組合為更復雜的組合對象,這個組合對象又可以被組合。
迭代器模式(Iterator),提供一種方法順序訪問一個聚合對象中各個元素,而又不暴露該對象的內部表示。
當你需要訪問一個聚集對象,而且不管這些對象是什么都需要遍歷的時候,你就應該考慮用迭代器模式。當你需要對聚集有多種方式遍歷時,可以考慮用迭代器模式。Java中的for-each
就是迭代器模式。
迭代器模式就是分離了集合對象的遍歷行為,抽象出一個選代器類來負責,這樣既可以做到不暴露集合的內部結構,又可讓外部代碼透明地訪問集合內部的數(shù)據(jù)。迭代器模式在訪問數(shù)組、集合、列表等數(shù)據(jù)時,尤其是數(shù)據(jù)庫數(shù)據(jù)操作時,是非常普遍的應用,但由于它太普遍了,所以各種高級語言都對它進行了封裝。
單例模式(Singleton),保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。
讓類自身負責保存它的唯一實例。這個類可以保證沒有其他實例可以被創(chuàng)建,并且它可以提供一個訪問該實例的方法(靜態(tài)方法)。
單例模式有多種實現(xiàn)方法,參考單例模式 | 菜鳥教程
一般采用餓漢式在類直接創(chuàng)建靜態(tài)對象:
public class Singleton { private static Singleton instance = new Singleton(); private Singleton (){} public static Singleton getInstance() { return instance; } }
如果明確需要使用懶加載,可以采用登記式/靜態(tài)內部類方式:
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; } }
橋接模式(Bridge),將抽象部分與它的實現(xiàn)部分分離,使它們都可以獨立地變化。(實現(xiàn)指的是抽象類和它的派生類用來實現(xiàn)自己的對象)。
實現(xiàn)系統(tǒng)可能有多角度分類,每一種分類都有可能變化,那么就把這種多角度分離出來讓它們獨立變化,減少它們之間的耦合。
例如為不同的手機開發(fā)游戲,可以將手機硬件和軟件分離,手機有A、B兩個品牌,軟件有M、N兩類。有一個抽象手機類,A手機、B手機繼承抽象手機類;有一個抽象軟件類,M軟件、N軟件繼承抽象軟件類;然后抽象手機類引用抽象軟件類。這樣不管增加手機還是增加軟件都很方便。
合成/聚合復用原則(CARP):盡量使用合成(組合) / 聚合,盡量不要使用類繼承。
命令模式(Command),將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數(shù)化;對請求排隊或記錄請求日志,以及支持可撤銷的操作。
例如點燒烤,我們是客戶端,服務員是Invoker,向廚師Receiver發(fā)送命令,其中有一個抽象的Command類用于聲明執(zhí)行操作的接口,ConcreteCommand類繼承Command類,(綁定接收者廚師Receiver)用于實現(xiàn)具體的動作。服務員Invoke是通過Command類來向廚師Receiver進行交互的。
【優(yōu)點】
敏捷開發(fā)原則告訴我們,不要為代碼添加基于猜測的、實際不需要的功能。
如果不清楚一個系統(tǒng)是否需要命令模式,一般就不要著急去實現(xiàn)它,事實上,在需要的時候通過重構實現(xiàn)這個模式并不困難,只有在真正需要如撤銷/恢復操作等功能時,把原來的代碼重構為命令模式才有意義。
職責鏈模式(Chain of Responsibility),使多個對象都有機會處理請求,從而避免請求的發(fā)送者和接收者之間的耦合關系。將這個對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理它為止。
比如,員工請假,不同管理者級別能處理的請假天數(shù)不一樣。設置一個管理者抽象類,有設置上級(繼任者)方法和處理請求的抽象方法,有多個級別的管理者繼承該抽象類,實現(xiàn)處理請求的抽象方法。這樣,員工(客戶端)每次都是向組長請假,組長批不了的就交由部門經(jīng)理處理,經(jīng)理處理不了的就由總監(jiān)處理。
中介者模式(Mediator),用一個中介對象來封裝一系列的對象交互。中介者使各對象不需要顯式地相互引用,從而使其耦合松散,而且可以獨立地改變它們之間的交互。
例如,聯(lián)合國安理會調節(jié)國家沖突。有一個聯(lián)合國抽象類,里面有調節(jié)抽象方法(參數(shù)為調節(jié)信息和調節(jié)對象),有具體的安理會繼承聯(lián)合國抽象類,實現(xiàn)具體方法;有國家抽象類,需要設置中介者,有具體國家類繼承國家抽象類,實現(xiàn)具體方法;在實際使用時,由中介者去調用國家類的方法。
中介者模式一般應用于一組對象以定義良好但是復雜的方式進行通信的場合,比如剛才得到的窗體Form對象或Web頁面aspx,以及想定制一個分布在多個類中的行為,而又不想生成太多的子類的場合。
【優(yōu)點】
Mediator的出現(xiàn)減少了各個Colleague的耦合,便得可以獨立地改變和復用各個Colleague類和Mediator。
由于把對象如何協(xié)作進行了抽象,將中介作為一個獨立的概念并將其封裝在一個對象中,這樣關注的對象就從對象各自本身的行為轉移到它們之間的交互上來,也就是站在一個更宏觀的角度去看待系統(tǒng)。
【缺點】
享元模式(Flyweight),運用共享技術有效地支持大量細粒度的對象。
比如為不同人創(chuàng)建類似的網(wǎng)站,可以把網(wǎng)站的公共部分抽取出來,將用戶設置為外部狀態(tài)傳進去。這樣的話,就算要為10個用戶創(chuàng)建網(wǎng)站,也可以只有一個網(wǎng)站實例。有用戶類,有一個抽象網(wǎng)站類,里面有抽象使用方法(傳入用戶),有多個具體的網(wǎng)站類,實現(xiàn)抽象方法;有一個網(wǎng)站工廠負責管理網(wǎng)站(沒有則創(chuàng)建,有則取出返回)。
如果一個應用程序使用了大量的對象,而大量的這些對象造成了很大的存儲開銷時就應該考慮使用;還有就是對象的大多數(shù)狀態(tài)可以外部狀態(tài),如果刪除對象的外部狀態(tài),那么可以用相對較少的共享對象取代很多組對象,此時可以考慮使用享元模式。
【優(yōu)點】
【缺點】
Java中的字符串(會放到字符串池中)就是用了享元模式。
解釋器模式(interpreter),給定一個語言,定義它的文法的一種表示,并定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。
比如正則表達式,可以用特定的文法去匹配字符串。
AbstractExpression類:抽象表達式。聲明一個抽象的解釋操作,這個接口為抽象語法樹中所有的節(jié)點所共享。
TerminalExpression類:終結符表達式。實現(xiàn)與文法中的終結符相關聯(lián)的解釋操作。實現(xiàn)抽象表達式中所要求的接口,主要是一個interpret() 方法。文法中每一個終結符都有一個具體終結表達式與之相對應。
NonterminalExpression類:非終結符表達式,為文法中的非終結符實現(xiàn)解釋操作。對文法中每一條規(guī)則 R1、R2……Rn 都需要一個具體的非終結符表達式類。通過實現(xiàn)抽象表達式的interpret() 方法實現(xiàn)解釋操作。解釋操作以遞歸方式調用上面所提到的代表R1、R2……Rn中各個符號的實例變量。
Context類:包含解釋器之外的一些全局信息。
訪問者模式(Visitor),表示一個作用于某對象結構中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。
比如,有男人、女人2種數(shù)據(jù)結構,每類人都有多個情緒,情緒對應的操作不同。有抽象訪問者類Visitor,為該對象結構中ConcreteElement的每一個類聲明一個Visit操作;ConcreteVisitor1和ConcreteVisitor2類,具體訪問者,實現(xiàn)每個由Visitor聲明的操作;人抽象類Element,定義一個Accept操作,它以一個訪問者為參數(shù);男人類 ConcreteElementA和女人類ConcreteElementB,具體元素,實現(xiàn)Accept操作;人的集合ObjectStructure類,能枚舉它的元素,可以提供一個高層的接口以允許訪問者訪問它的元素。
Accept操作充分利用雙分派技術,實現(xiàn)處理與數(shù)據(jù)結構的分離。
在客戶程序中將具體狀態(tài)作為參數(shù)傳遞給男人類完成了一次分派,然后男人類調用作為參數(shù)的具體狀態(tài)中的方法男人反應,同時將自己(this)作為參數(shù)傳遞進去。這便完成了第二次分派。雙分派意味著得到執(zhí)行的操作決定于請求的種類和兩個接收者的類型。接受方法就是一個雙分派的操作,它得到執(zhí)行的操作不僅決定于狀態(tài)類的具體狀態(tài),還決定于它訪問的人的類別。
訪問者模式適用于數(shù)據(jù)結構相對穩(wěn)定的系統(tǒng),它把數(shù)據(jù)結構和作用于結構上的操作之間的耦合解脫開,使得操作集合可以相對自由地演化。
【優(yōu)點】
【缺點】
訪問者模式的目的是要把處理從數(shù)據(jù)結構分離出來。很多系統(tǒng)可以按照算法和數(shù)據(jù)結構分開,如果這樣的系統(tǒng)有比較穩(wěn)定的數(shù)據(jù)結構,又有易于變化的算法的話,使用訪問者模式就是比較合適的,因為訪問者模式使得算法操作的增加變得容易。反之,如果這樣的系統(tǒng)的數(shù)據(jù)結構對象易于變化,經(jīng)常要有新的數(shù)據(jù)對象增加進來,就不適合使用訪問者模式。
創(chuàng)建型模式 --> 對象怎么來
抽象工廠模式:提供一個創(chuàng)建一系列或相關依賴對象的接口,而無需指定它們具體的類。
建造者模式:將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創(chuàng)建不同的表示。
工廠方法模式:定義一個用于創(chuàng)建對象的接口,讓子類決定實例化哪一個類,工廠模式使一個類的實例化延遲到其子類。
原型模式:用原型實例指定創(chuàng)建對象的種類,并且通過拷貝這些原型創(chuàng)建新的對象。
單例模式:保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。
創(chuàng)建型模式隱藏了這些類的實例是如何被創(chuàng)建和放在一起,整個系統(tǒng)關于這些對象所知道的是由抽象類所定義的接口。這樣,創(chuàng)建型模式在創(chuàng)建了什么、誰創(chuàng)建它、它是怎么被創(chuàng)建的,以及何時創(chuàng)建這些方面提供了很大的靈活性。
結構型模式 --> 對象和誰有關
適配器模式:將一個類的接口轉換成客戶希望的另外一個接口。適配器模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。
橋接模式:將抽象部分與它的實現(xiàn)部分分離,使它們都可以獨立地變化。
組合模式:將對象組合成樹形結構以表示“部分-整體”的層次結構,組合模式使得用戶對單個對象和組合對象的使用具有一致性。
裝飾器模式:動態(tài)地給一個對象添加一些額外的職責。就增加功能來說,裝飾模式相比生成子類更加靈活。
外觀模式:為子系統(tǒng)中的一組接口提供一個一致的界面,外觀模式定義了一個高層接口,這個接口使得這一子系統(tǒng)更加容易使用。
享元模式:運用共享技術有效地支持大量細粒度的對象。
代理模式:為其他對象提供一種代理以控制對這個對象的訪問。
行為型模式 --> 對象與對象在干嘛
觀察者模式:定義對象間的一種一對多的依賴關系,當一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都得到通知并被自動更新。
模板方法模式:定義一個操作的算法骨架,而將一些步驟延遲到子類中,模板方法使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。
命令模式:將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數(shù)化;可以對請求排隊或記錄請求日志,以及支持可撤銷的操作。
狀態(tài)模式:允許一個對象在其內部狀態(tài)改變時改變它的行為,讓對象看起來似乎修改了它的類。
職責鏈模式:多個對象都有機會處理請求,從而避免請求的發(fā)送者和接收者之間的耦合關系。將這些對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理它為止。
解釋器模式:給定一個語言,定義它的文法的一種表示,并定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。
中介者模式:一個中介對象來封裝一系列的對象交互。中介者使各對像不需要顯式地相互引用,從而使其耦合松散,而且可以獨立地改變它們之間的交互。
訪問者模式:表示一個作用于某對象結構中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。
策略模式:定義一系列的算法,把它們一個個封裝起來,并且使它們可相互替換,使得算法可獨立于使用它的客戶而變化。
備忘錄模式:在不破壞封裝性的前提下,捕獲一個對象的內部狀態(tài),并在該對象之外保存這個狀態(tài)。這樣以后就可將該對象恢復到原先保存的狀態(tài)。
迭代器模式:提供一種方法順序訪問一個聚合對象中各個元素,而又不需暴露該對象的內部表示。