JAVA設計模式,附贈demo

近日讀了大話設計模式,進一步鞏固了自己對設計模式的理解。
現將學習筆記整理出來,供自己和要學設計模式的童鞋參考。
設計模式之間有很多相似之處,即便整體學過以後也要經常複習。
爲了複習方便我講java設計模式一一對應的demo整理的java項目打包,供以後開發中想到需求和某一設計模式掛鉤時參考使用。

github地址:https://github.com/xiaoyao880609/design_patterns-demo

UML 常用圖標說明:
--→:依賴關係【體現爲局域變量、方法的形參,或者對靜態方法的調用】
→:關聯關係【成員變量定義關聯實體類屬性,可雙向,也可單向】
△→:繼承關係
△--→:實現關係
◇→:聚合關係(弱擁有關係,生命週一不同步)【成員變量定義實體類集合屬性】
◆→:合成關係(強擁有關係,生命週期同步)【成員變量定義實體類集合屬性,類初始化同時初始化組合類】
=======================================================================
單一原則:又稱單一功能原則,它規定一個類應該只有一個發生變化的原因。
開放-封閉原則:是說軟件實體(類,模塊,函數等等)應該可以擴展,但不可修改。
依賴倒轉原則:抽象不應該依賴細節,細節應該依賴於抽象。(面向接口編程)
里氏代換原則(對依賴倒轉的補充):只有衍生類可以替換掉基類,軟件單位功能不受影響時,基類才能真正被複用。
迪米特法則-LoD:如果兩個類不必彼此直接通訊,那麼這兩個類就不應該發生直接的相互作用。如果其中一個類需要調用另一個類的某一個方法,可以通過第三者轉發這個調用。
合成/聚合複用原則:優先使用對象合成/聚合,而不是繼承。
=======================================================================
簡單工廠:計算器例子:超類計算器。加,減,乘,除繼承超類,創建生成具體計算器,接受(算法符號)來生成對應的算法計算器實例。


工廠方法模式:定義一個用於創建工廠對象的接口,讓子類決定實例化哪一個類。工廠方法使一個類的實例化延遲到其子類。
創建工廠接口。加,減,乘,除工廠實現工廠接口返回具體加,減,乘,除實例。
客戶端實體化具體加,減,乘,除工廠類,通過工廠接口獲取具體實例

區別:簡單工廠模式最大優點在於工廠類包含了必要的邏輯判斷,根據客戶端的選擇條件動態實例化相關類,對於客戶端去除了具體產品的依賴。
新加功能時需要修改原有工廠類中的邏輯,不符合開閉原則(對擴展開放,修改關閉)。
工廠方法把簡單工廠的內部邏輯判斷移到了客戶端代碼來進行。你想要加功能,本來需要改工廠類的,而現在是修改客戶端。
-----------------------------------------------------------------------
抽象工廠模式:提供一個創建一系列相關或相互依賴對象的接口,而無需指定他們具體的類。
抽象工廠接口(有多個實現):包含所有產品創建的抽象方法。
抽象產品接口(有多個實現):定義所有產品抽象方法。
具體工廠類繼承抽象工廠方法,依賴具體抽象產品類。
客戶端通過多態引用抽象工廠創建產品。
優點:由於抽象工廠在一個應用中只需要初始化時候出現一次,使得改變具體工廠變得簡單,只需要改變具體工廠即可使用不同的產品配置。

客戶端通過抽象接口操控實例,使具體工廠的實現分離。


-----------------------------------------------------------------------
策略模式:(算法的變化不影響使用算法的客戶。好處:1,:通過繼承可以得到公共功能,2:算法之間相互獨立,互不干擾,利於單元測試)
策略類(抽象類)定義所有支持算法的公共接口。多個具體算法子類繼承策略類實現超類中的抽象方法。
上下文類(負責維護隊策略類對象的引用)通過構造方法初始化超類-策略類對象,提供公開方法返回具體策略類算法的結果
客戶端:通過註冊具體算法實現類來獲取上下文類。運行公開算法方法獲取結果(因此做到了具體算法的實現與客戶端完全分離)

總結:只要在分析過程中不同的時間應用不同的業務規則時候可以考慮使用策略模式!


-----------------------------------------------------------------------
裝飾模式:動態地給對象添加額外的職責,就增加功能來說裝飾模式比生成子類更靈活。
(在原有功能基礎上不變動原始類擴展來調用原始方法後添加自己獨有的功能)
Component-對象抽象接口:定義一個對象抽象接口提供抽象方法(動態添加職責,無需知道Decorator)
ConcreteComponent-具體對象實例:實現對象接口
Decorator-裝飾抽象類:繼承接口對象構造函數接收ConcreteComponent初始化protected的Component屬性(多態),
調用Component的具體方法重寫父類抽象方法。
ConcreteDecorator-裝飾實體類(多個):繼承Decorator-裝飾抽象類,重寫原始方法,先執行super父類的原始方法後面添加新功能實

總結:裝飾模式是爲已有功能基礎上動態地添加更多功能的一中方式。有效的把類的核心職責和裝飾功能區分開,並且可以去除相關類中重複的裝飾邏輯。


-----------------------------------------------------------------------
代理模式:爲其他對象提供一種代理以控制對這個對象的訪問。
定義要代理的接口。
委託人實現代理接口中的方法。
代理類中關聯委託人實體類,用關聯的委託人的方法實現代理接口中的方法。

客戶端初始化代理類來調用委託人的方法(對於客戶端委託人的隱藏的)


-----------------------------------------------------------------------

原型模式- Prototype:用原型實例指定創建對象的種類,並且通過拷貝這些原型創建新的對象。

潛複製-基本類型複製值,引用對象複製引用地址:java中必須要實現Cloneable接口(通知虛擬機可複製)調用super.clone()方法就可以實現原型模式。

深複製-基本類型複製值,引用對象複製引用具體實例:被複制對象必須實現Serializable接口,用流寫和讀取的方式實現深複製。 (把對象寫到流裏的過程是序列化(Serialization)過程;而把對象從流中讀出來的過程則叫反序列化(Deserialization)過程)

ByteArrayOutputStream baos =new ByteArrayOutputStream();
newObjectOutputStream(baos).writeObject(oldObj);
return newObj = newObjectInputStream(newByteArrayInputStream(baos.toByteArray())).readObject();


-----------------------------------------------------------------------
模板方法模式:定義一個操作中算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。
抽象模板(Abstract Template)角色:定義了一個或多個抽象操作,以便讓子類實現。這些抽象操作叫做基本操作,它們是一個頂級邏輯的組成步驟。
定義並實現了一個模板方法。這個模板方法一般是一個具體方法,它給出了一個頂級邏輯的骨架,而邏輯的組成步驟在相應的抽象操作中,推遲到子類實現。頂級邏輯也有可能調用一些具體方法。
具體模板(Concrete Template)角色:實現父類所定義的一個或多個抽象方法,它們是一個頂級邏輯的組成步驟。

每一個抽象模板角色都可以有任意多個具體模板角色與之對應,而每一個具體模板角色都可以給出這些抽象方法(也就是頂級邏輯的組成步驟)的不同實現,從而使得頂級邏輯的實現各不相同。


-----------------------------------------------------------------------
外觀模式-門面模式(依賴倒轉原則 + 迪米特法則-LoD):把一些複雜的流程封裝成一個接口(門面角色)給外部用戶更簡單的使用

門面角色:外觀模式的核心。將被客戶端角色調用,內部根據客戶角色的需求封裝子系統角色功能的組合,從而提供給客戶角色調用。


-----------------------------------------------------------------------
建造者模式:將一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。
可以用同一個接口創建複雜的屬性不同的產品對象。
創建抽象的建造者類-Builder,聲明抽象的建造詳細流程。
具體建造類-ConcreteBuilder繼承抽象建造者類,實現具體建造流程。(多個)

指揮者-Director包含具體建造者,構造函數初始化後(傳入具體建造類),封裝具體建造流程提供客戶端調用。


-----------------------------------------------------------------------
觀察者模式:定義了一對多的依賴關係,讓多個觀察者對象同時監聽某一個主題對象,當主題對象狀態變化時通知所有觀察者更新自己。
主題或者抽象通知者-Subject(抽象類)包含觀察者集合和狀態標識,提供加減集合方法,和通知方法-Notify(循環集合調用觀察者的更新方法),
抽象觀察者-Observer爲所有具體觀察者定義一個接口,在收到主題通知時更新自己。
客戶端當修改具體主題的狀態標識時調用notify方法批量更新觀察者。

應用場景:當一個對象改變,需要同時改變其他多個對象。


-----------------------------------------------------------------------
狀態模式-State:主要解決當控制一個對象狀態轉換的條件表達式過於複雜時,把狀態的判斷邏輯轉移到表示不同狀態的一系列類當中,可以把複雜的判斷邏輯簡化。
抽象狀態類-State(接收當前狀態-Context):定義一個接口以封裝與Context的一個特定狀態相關的行爲。
具體狀態類(多個):實現每一個狀態對應的行爲,首先判斷當前狀態是否和具體狀態一致,一致執行行爲後變更下一個狀態,否則先變更Context爲下一個狀態在執行行爲。

Context中維護一個具體狀態類來定義當前狀態。


-----------------------------------------------------------------------
適配器模式-Adapter:項目後期維護中,2個類所做的事情相同,只是接口不同時可以通過適配器優化。

定義一個適配器繼承目標-Target類,引用被適配者類,通過調用被適配者類中方法重寫父類-Target的方法。
Target:目標角色,期待得到的接口.
Adaptee:適配者角色,被適配的接口.

Adapter:適配器角色,將源接口轉換成目標接口.


-----------------------------------------------------------------------
備忘錄模式又叫快照模式-Snapshot Pattern:不破壞封裝的條件下,將一個對象的狀態捕捉(Capture)住,並外部化,存儲起來,從而在合適的時候將對象還原到存儲時的狀態。
發起人-Originator:負責創建Memento,記錄當前時刻自身的內部狀態,並可使用備忘錄恢復內部狀態(提供保存備忘錄和恢復方法)。
備忘錄-Memento:負責存儲發起人的內部狀態,並防止發起人以外的對象訪問(定義私有變量提供初始化,但不提供訪問接口)。
管理者:持有備忘錄,並提供初始化和獲取方法。

客戶端:將備忘錄信息初始化後保存到管理者中。需要恢復時通過事前定義好的管理者持有的備忘錄調用恢復方法。


-----------------------------------------------------------------------
組合模式:組合多個對象形成樹形結構以表示"整體-部分"的結構層次。對單個對象或者組合對象具有一致性。
Component 抽象接口:組合中對象聲明接口,用於訪問和管理Component子部件。
Leaf實現Component:葉子對象,沒有子節點。

Composite實現Component:容器對象,定義有枝節點行爲,用來存儲子部件。實現Component中聲明的子部件相關操作,比如增加和刪除。


-----------------------------------------------------------------------
迭代器模式-Iterator:提供一種方法順序訪問一個聚合對象中的各種元素,而又不暴露該對象的內部表示。(JAVA已經內部封裝不需要自己實現該模式)
迭代器角色(Iterator):定義遍歷元素所需要的取得下一個元素的方法next(),判斷是否遍歷結束的方法hasNext()),移出當前對象的方法remove()。
具體迭代器角色(Concrete Iterator):實現迭代器接口中定義的方法,完成集合的迭代。
容器角色(Aggregate):一般是一個接口,提供一個iterator()方法,例如java中的Collection接口,List接口,Set接口等

具體容器角色(ConcreteAggregate):就是抽象容器的具體實現類,比如List接口的有序列表實現ArrayList,List接口的鏈表實現LinkList,Set接口的哈希列表的實現HashSet等。


-----------------------------------------------------------------------

單例模式-Singleton(太簡單不整理):保證一個類僅有一個實例,並提供全局獲取方法。


-----------------------------------------------------------------------
橋接模式(合成/聚合複用原則):實現系統可能有多角度分類,每一種分類都有可能變化,那麼就把這種角度分離出來讓他們獨立,用合成/聚合的關係關聯,減少它們之間的耦合。
抽象接口定義一個分類的超類,子類實現這個超類。(多個軟件)

抽象類表示另一個分類的超類與抽象接口是聚合/合成關係,構造函數接口抽象接口的具體子類。調用抽象接口子類方法來實現。

Abstraction(抽象類):用於定義抽象類的接口,它一般是抽象類而不是接口,其中定義了一個Implementor(實現類接口)類型的對象並可以維護該對象,它與Implementor之間具有關聯關係,它既可以包含抽象業務方法,也可以包含具體業務方法。

RefinedAbstraction(擴充抽象類):擴充由Abstraction定義的接口,通常情況下它不再是抽象類而是具體類,它實現了在Abstraction中聲明的抽象業務方法,在RefinedAbstraction中可以調用在Implementor中定義的業務方法。

Implementor(實現類接口):定義實現類的接口,這個接口不一定要與Abstraction的接口完全一致,事實上這兩個接口可以完全不同,一般而言,Implementor接口僅提供基本操作,而Abstraction定義的接口可能會做更多更復雜的操作。Implementor接口對這些基本操作進行了聲明,而具體實現交給其子類。通過關聯關係,在Abstraction中不僅擁有自己的方法,還可以調用到Implementor中定義的方法,使用關聯關係來替代繼承關係。

ConcreteImplementor(具體實現類):具體實現Implementor接口,在不同的ConcreteImplementor中提供基本操作的不同實現,在程序運行時,ConcreteImplementor對象將替換其父類對象,提供給抽象類具體的業務操作方法。


-----------------------------------------------------------------------
命令模式-Command:將一個請求封裝一個對象,從而使你可用不同的請求對客戶進行參數化,對請求排隊或記錄請求日誌,以及支持可撤回操作。
抽象命令角色,命令超類,聲明瞭一個給所有具體命令類的抽象接口。
具體命令角色,定義一個接收者和行爲之間的弱耦合;實現execute()方法,負責調用接收者的相應操作。execute()方法通常叫做執行方法。
請求者角色-Invoker,與Command是聚合關係。負責調用命令對象執行請求,相關的方法叫做行動方法。

接收者角色-Receiver,負責具體實施和執行一個請求。任何一個類都可以成爲接收者,實施和執行請求的方法叫做行動方法。


-----------------------------------------------------------------------
職責鏈模式-Chain of Responsibility:使多個對象都有機會處理請求,從而避免請求者和接收者之間的耦合關係。將這個對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它爲止。
處理請示的接口-Handler:與它的子類-繼任者是聚合關係,提供方法設置繼任者。並提供抽象的處理請求方法。

繼任者-Successor(Handler子類):包含繼任者,處理請求方法中先判斷是否有執行權,若沒有調用繼任者處理請求方法,委託給下一任處理請求。


-----------------------------------------------------------------------
中介者模式-Mediator(與同事類-Colleague是聚合關係):用一箇中介對象來封裝一系列對象交互。中介者使各對象不需要顯示地相互引用,從而使其耦合鬆散,而且可以獨立地改變它們之間的交互。
抽象中介者-Mediator:定義同事對象到中介者對象的接口。定義一個抽象的發送消息方法,得到同事對象和發送信息。
具體中介者:者實現Mediator接口,它需要知道所有具體同事類(擁有所有同事類的成員變量),並從具體同事接收消息,並且給具體同事對象發出命令。
抽象同事類-Colleague:構造方法,初始化成員變量-中介者對象 。
具體同事類:繼承抽象同事類,通過構造函數註冊具體中介者對象,使每個具體同事類都與中介建立聯繫。(每個具體同事類相對獨立)
總結:Mediator減少了各個Colleague的耦合,使得可以獨立地改變和複用各個Colleague和Mediator類。但由於具體中介類中控制了集中化,因此把交互複雜性變爲了中介者的複雜性。
中介者模式一般用於一組對象以定義良好但複雜的方式進行通信的場合,以及想定製一個分佈在多個類中的行爲,而又不行生成太多子類的場合。


-----------------------------------------------------------------------
享元模式-Flyweight:採用一個共享來避免大量擁有相同內容對象的開銷。最常見、直觀的就是內存損耗。享元模式以共享的方式高效的支持大量的細粒度對象。
(目的,使對象共享,減少內存損耗,享元對象能做到共享的關鍵是區分內蘊狀態-Internal State和外蘊狀態-External State)
內蘊狀態-Internal State:一個內蘊狀態是存儲在享元對象內部的,並且是不會隨環境的改變而有所不同。
外蘊狀態-External State:一個外蘊狀態是隨環境的改變而改變的、不可以共享的。享元對象的外蘊狀態必須由客戶端保存,並在享元對象被創建之後,在需要使用的時候再傳入到享元對象內部。外蘊狀態不可以影響享元對象的內蘊狀態,它們是相互獨立的。
抽象享元角色-Flyweight:給出一個抽象接口,以規定出所有具體享元角色需要實現的方法,參數接收外蘊狀態。
具體享元角色-ConcreteFlyweight:實現抽象享元角色規定的方法。如果存在內蘊狀態,就負責爲內蘊狀態提供存儲空間。構造函數,內蘊狀態作爲參數傳入。
享元工廠角色:負責創建和管理享元角色。要想達到共享的目的,這個角色的實現是關鍵!
(定義Map<內蘊狀態,享元對象>來維護享元角色對象,先通過內蘊狀態從Map中獲取,如果沒有、通過內蘊創建享元對象放入Map中再返回該對象)

客戶端角色:維護對所有享元對象的引用,而且還需要存儲對應的外蘊狀態。

▽▽▽▽▽▽▽▽▽▽▽▽▽▽複合享元模式▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽
複合享元角色-ConcreteCompositeFlyweight :複合享元角色所代表的對象是不可以共享的,但是一個複合享元對象可以分解成爲多個本身是單純享元對象的組合。複合享元角色又稱作不可共享的享元對象(實現抽象抽象享元角色,定義Map<內蘊狀態,享元對象>來維護複合享元角色對象,並且提供公開的添加複合享元對象到Map的方法)

享元工廠角色中額外提供複合享元工廠方法,參數接收內蘊狀態集合。遍歷集合調用複合享元角色中的添加方法批量將享元工廠方法獲取到的享元角色添加到複合享元Map中。


-----------------------------------------------------------------------
解釋器模式-Interpreter:類的行爲模式。給定一個語言之後,解釋器模式可以定義出其文法的一種表示,並同時提供一個解釋器。客戶端可以使用這個解釋器來解釋這個語言中的句子。
抽象表達式-Expression角色:聲明一個所有的具體表達式角色都需要實現的抽象接口。這個接口主要是一個interpret()方法,稱做解釋操作。
終結符表達式-Terminal Expression角色:實現了抽象表達式角色所要求的接口,主要是一個interpret()方法;文法中的每一個終結符都有一個具體終結表達式與之相對應。比如有一個 簡單的公式R=R1+R2,在裏面R1和R2就是終結符,對應的解析R1和R2的解釋器就是終結符表達式。
非終結符表達式-Nonterminal Expression角色:文法中的每一條規則都需要一個具體的非終結符表達式,非終結符表達式一般是文法中的運算符或者其他關鍵字,比如公式R=R1+R2中, “+"就是非終結符,解析“+”的解釋器就是一個非終結符表達式。

環境-Context角色:這個角色的任務一般是用來存放文法中各個終結符所對應的具體值,比如R=R1+R2,我們給R1賦值100,給R2賦值200。這些信息需要存放到環境角色中,很多情況下我們使用Map來充當環境角色就足夠了。


-----------------------------------------------------------------------
訪問者模式-Visitor:表示一個作用於某對象結構中的各元素的操作。它使你可以再不改變各元素的類的前提下定義作用於這些元素的新操作。
(數據結構和操作分離,使得在數據結構不變的前提下,很容易添加新操作)
Visitor(抽象訪問者-抽象出訪問元素的動作):在重載的visit函數中聲明訪問者可以訪問的對象。
Concrete Visitor(具體訪問者-實現訪問元素的動作):實現一個訪問者對於一個具體的元素的操作
Element(抽象元素-定義一個接受訪問的操作,其參數爲訪問者):聲明具有訪問該類型元素權限的訪問者的類型(一般是抽象類型),提供重載的accept函數賦予權限。
Concrete Element(具體元素-實現接受訪問操作):實現accept方法,基本上是模板化的visitor.visit(this)
Object Structure(對象結構類-可以枚舉元素,並且管理元素):容納多種類型或許不同,接口或者不同的元素的集合。
有以下情形可以考慮使用訪問者模式:
1、一個對象結構包含很多類對象,它們有不同的接口,而你想對這些對象實施一些依賴於其具體類的操作。
2、需要對一個對象結構中的對象進行很多不同的並且不相關的操作,而你想避免讓這些操作“污染”這些對象的類。Visitor使得你可以將相關的操作集中起來定義在一個類中。
3、當該對象結構被很多應用共享時,用Visitor模式讓每個應用僅包含需要用到的操作。
4、 定義對象結構的類很少改變,但經常需要在此結構上定義新的操作。改變對象結構類需要重定義對所有訪問者的接口,這可能需要很大的代價。如果對象結構類經常改變,那麼可能還是在這些類中定義這些操作較好。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章