這部分太多了,自己學(xué)習(xí)的時候有側(cè)重,自己整理總結(jié)的筆記是紙質(zhì)版的,學(xué)習(xí)這部分的時候主要是看了網(wǎng)上的demo,以及《Head First設(shè)計模式》(這本書我覺得推薦度一般,因為廢話實在太多了...).《大話設(shè)計模式》聽說很多人買,之前買過《大話數(shù)據(jù)結(jié)構(gòu)》感覺大話系列的蠻容易看懂的,所以推薦下可以去看這本。
面向?qū)ο笤O(shè)計模式可分為三類:(創(chuàng)建、結(jié)構(gòu)、行為)
創(chuàng)建型模式:工廠模式、抽象工廠模式、生成器模式、單例模式、原型模式
結(jié)構(gòu)型模式:(類)適配器模式、(對象)適配器模式、橋接模式、組合模式、裝飾模式、外觀模式、享元模式、代理模式
行為模式:策略模式、模板方法模式、觀察者模式、迭代子模式、責(zé)任鏈模式、命令模式、備忘錄模式、狀態(tài)模式、訪問者模式、中介者模式、解釋器模式。

一、創(chuàng)建型模式:(5)
1、工廠模式【工廠模式 - 簡書】
工廠方法模式:
一個抽象產(chǎn)品類,可以派生出多個具體產(chǎn)品類。?
一個抽象工廠類,可以派生出多個具體工廠類。?
每個具體工廠類只能創(chuàng)建一個具體產(chǎn)品類的實例。

2、抽象工廠模式:
多個抽象產(chǎn)品類,每個抽象產(chǎn)品類可以派生出多個具體產(chǎn)品類。
一個抽象工廠類,可以派生出多個具體工廠類。?
每個具體工廠類可以創(chuàng)建多個具體產(chǎn)品類的實例,也就是創(chuàng)建的是一個產(chǎn)品線下的多個產(chǎn)品。?

總結(jié):
a.簡單工廠,不是設(shè)計模式,是一個方法,讓客戶程序從具體類解耦
b.工廠:使用繼承,把對象的創(chuàng)建委托給子類,子類實現(xiàn)工廠方法來創(chuàng)建對象;
抽象工廠:對象組合,對象的創(chuàng)建被實現(xiàn)在工廠接口所暴露的方法中。創(chuàng)建相關(guān)的對象家族。
c.所有工廠模式都通過減少應(yīng)用程序和具體類間的依賴促進(jìn)松耦合。
3、生成器模式:
4、單例模式:可以保證系統(tǒng)中一個類只有一個實例而且該實例易于外界訪問,從而方便對實例個數(shù)的控制并節(jié)約系統(tǒng)資源。
私有的實例,私有的構(gòu)造方法,提供了一個公共的提供唯一實例的方法
使用:用來管理共享的資源,如數(shù)據(jù)庫連接或線程池。
設(shè)計思路
要創(chuàng)建的對象的類只有一個私有的構(gòu)造函數(shù),構(gòu)造函數(shù)中定義了唯一的單例對象,外界只能通過getInstance()方法得到對象實例,且每次都只能生成唯一的對象。

如果不用單例模式而使用全局變量的話:
全局變量可以提供全局訪問,但不能確保只有一個實例。用許多全局變量指向許多小對象造成命名空間污染。
單例模式幾種形式:Java設(shè)計模式之單例模式詳解 - garryfu - 博客園
a.餓漢式:立即加載,類加載初期就創(chuàng)建好了靜態(tài)對象,線程安全的。
```
public class Singleton1{
? ? ? private Singleton1(){}
? private static Singleton1 single=new Singleton1();
public static Singleton1 getInstance(){
? ? return single;
? ?}
}
```
b.懶漢式:延遲加載,類似上圖,一開始對象是null,非線程安全。
但會產(chǎn)生多個,所以要加synchronized,加同步鎖/同步代碼塊,但運行效率低下
==>加雙重檢查和synchronized,優(yōu)化,避免了整個方法被鎖,提高了執(zhí)行效率
```
雙重檢查:
public class Singleton4{
? ? ?private Singleton4(){}
private static Singleton4 single=null;
? public statci Singleton4 getInstance(){
? ? ? ? ? if(single==null)? {
? ? ? ? ? ? ? ? ?synchronized(Singleton4.class){
? ? ? ? ? ? ? ? ? ? ? ? if(single==null){
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? single=new Singleton4();? }
? ? ? ? ? ? ? ? }? ?
? ?}return single;
}??
}
```
c.靜態(tài)內(nèi)部類實現(xiàn)
d.靜態(tài)代碼塊實現(xiàn)
e.內(nèi)部枚舉類實現(xiàn)
5、原型模式??設(shè)計模式之原型模式 - 簡書
創(chuàng)建一個對象之后的多個對象都可以拷貝原型來創(chuàng)建。
具體實現(xiàn)是:繼承Cloneable接口,重寫Clone()方法


二、結(jié)構(gòu)型模式:(7種)
1、適配器模式:
(1)類適配器模式把一個類的接口變換成客戶端所期待的另一種接口,從而使原本因接口不匹配而無法在一起工作的兩個類能夠在一起工作
思路:類適配器,指的是適配器Adapter繼承我們的被適配者Adaptee,并實現(xiàn)目標(biāo)接口Target。

(2)對象適配器模式:
適配器模式把一個類的接口變換成客戶端所期待的另一種接口,從而使原本因接口不匹配而無法在一起工作的兩個類能夠在一起工作。
解決設(shè)計思路:
對象適配器,簡單的說就是適配器實現(xiàn)我們的目標(biāo)接口,但是并不繼承需要被適配的類。而是通過在適配器的構(gòu)造函數(shù)中將需要被適配的類傳遞進(jìn)來從而進(jìn)行適配。

2、裝飾器模式:(最體現(xiàn)擴(kuò)展性)
裝飾模式就是給一個對象增加一些新的功能,而且是動態(tài)的,要求裝飾對象和被裝飾對象實現(xiàn)同一個接口,裝飾對象持有被裝飾對象的實例,關(guān)系圖如下:

可以用一個或多個裝飾者包裝一個對象。
裝飾者和被裝飾者對象有相同的超類型,所以在任何需要原始對象(被包裝)的場合,可用裝飾過的對象代替它。
裝飾者可以在所委托被裝飾者的行為之前/之后,加上自己的行為,以達(dá)到特定目的。

調(diào)用時:被裝飾者在最底層,被裝飾者一層層包裝,可以包裝多次。
```
Beverage? b=new Beverage();
b=new Mocha(b);
b=new Mocha(b);
b=new Milk(b);
System.out.println(b.getDes()+ b.cost());
```
擴(kuò)展:java.io包使用了裝飾者模式
【抽象組件:InputSream
具體的抽象組件/被裝飾類:FileInputStream、StringBufferInputStream、ByteArrayInputStream...
抽象裝飾者:FilterInputStream
具體組件/裝飾類:PushbackInputStream、BufferedInputStream、DataInputStream
】
缺點是:設(shè)計時會加入大量小類。在實例化組件時,還要把此組件包裝進(jìn)去,增加了代碼復(fù)雜度。
優(yōu)點:適合建立有彈性的設(shè)計、維持開放-關(guān)閉原則。
3、代理模式(Proxy):
代理模式就是多一個代理類出來,替原對象進(jìn)行一些操作。



4、外觀模式:
外觀模式是為了解決類與類之家的依賴關(guān)系的,像spring一樣,可以將類和類之間的關(guān)系配置到配置文件中,而外觀模式就是將他們的關(guān)系放在一個Facade類中,降低了類類之間的耦合度,該模式中沒有涉及到接口,看下類圖:(我們以一個計算機(jī)的啟動過程為例)

5、橋接模式:
橋接模式就是把事物和其具體實現(xiàn)分開,使他們可以各自獨立的變化。橋接的用意是:將抽象化與實現(xiàn)化解耦,使得二者可以獨立變化。
像我們常用的JDBC橋DriverManager一樣,JDBC進(jìn)行連接數(shù)據(jù)庫的時候,在各個數(shù)據(jù)庫之間進(jìn)行切換,基本不需要動太多的代碼,甚至絲毫不用動,原因就是JDBC提供統(tǒng)一接口,每個數(shù)據(jù)庫提供各自的實現(xiàn),用一個叫做數(shù)據(jù)庫驅(qū)動的程序來橋接就行了。我們來看看關(guān)系圖:



6、組合模式:
(1)安全組合模式:將對象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)。Composite使得用戶對單個對象和組合對象的使用具有一致性。

(2)一致性組合模式:

7、享元模式:
享元模式的主要目的是實現(xiàn)對象的共享,即共享池,當(dāng)系統(tǒng)中對象多的時候可以減少內(nèi)存的開銷,通常與工廠模式一起使用。
三、行為型模式:(11)
1、策略模式
2、模板方法模式
3、觀察者模式:(出版者/主題+訂閱者/觀察者)
a.? 定義了對象之間的一對多依賴,一個對象改變狀態(tài)時,它的所有依賴者都會收到通知并自動更新。

在subject接口和observer接口中直接寫就可以了。
在concreteSubject類,要實現(xiàn)subject接口,可以創(chuàng)建一個ArrayList<Observer> 存放的是所有注冊該主題的觀察者,如果register()就是往list中add()一個observer,remove()就是remove一個observer,notify()相當(dāng)于遍歷整個list,對每個observer對象進(jìn)行update()。
在concreteObserver類,實現(xiàn)Observer接口,有一個Subject的對象,其構(gòu)造函數(shù),相當(dāng)于注冊了一個新的觀察者,所以是需要subject需要注冊的主題為傳入?yún)?shù),并調(diào)用其的register()方法,相當(dāng)于在該主題注冊了新對象。其update()方法,當(dāng)其被concreteSubject的實體對象調(diào)用時,會傳入?yún)?shù),也就是給這個觀察者對象做了通知。
b.? ?此外?。。?!java API有內(nèi)置的觀察者模式,java.util包有包含基本的Observer接口和Observable類,類似于Subject接口和Observer接口,可以進(jìn)行push()、pull()傳送數(shù)據(jù)。
Observable接口的方法:addObserver()? deleteObserver()? notifyObserver()? setChanged()
現(xiàn)在concreteSubject類繼承Observable類,并繼承其addr、remove、notify()等方法。
對concreteObserver,要把對象變成觀察者:實現(xiàn)Observer接口,然后構(gòu)造方法中傳入observer對象,并調(diào)用其addObserver()方法;不想當(dāng)觀察者,則調(diào)用deleteObserver()
觀察者送出通知:在concretObserver類觀察者中構(gòu)造concreteSubject類,調(diào)用其setChanged()方法,標(biāo)記狀態(tài)已經(jīng)改變;調(diào)用其notifyObservers()或notifyObservers(Object arg)//傳任何數(shù)據(jù)對象
【推和拉:
拉:
setChanged():改變狀態(tài),到達(dá)某種條件,才調(diào)用該方法,使changed變?yōu)閠rue,進(jìn)行通知。這樣可以避免不必要的通知。這個時候傳送通知的方式是“拉”??
notyfyObservers(Object arg):源代碼會先判斷是否發(fā)生了changed,true才通知觀察者,通知后將changed標(biāo)志又設(shè)回false
推:
沒有setChanged(),和之前一樣,就是直接notify(),不用通知者自己來調(diào)用setChanged()和notify()的,就是推。
】
觀察者接收通知:同之前的update(Observerable o,Object arg)? //傳任何數(shù)據(jù)對象
但是?。?/p>
1、java.util.Observable是一個類,因此某類要同時有Observable和其他超類行為,就會困難(因為單繼承),限制了其復(fù)用潛力。
2、除非繼承Observable類,否則無法創(chuàng)建Observable的實例并組合到你自己的對象中(特別是setChanged()是protected的)
c.? JDK中的使用:
JButton
4、迭代子模式、
5、責(zé)任鏈模式
6、命令模式:將請求封裝成對象,以便使用不同的請求、隊列或者日志來參數(shù)化其他對象。
命令對象封裝動作和接收者,而只暴露出execute(),當(dāng)該方法調(diào)用,接收者會進(jìn)行動作。

Client:是測試類
Command接口:只有execute()方法
ConcreteCommand類:具體命令,其中有Receiver具體接受類對象,實現(xiàn)了Command接口,其方法主要是重寫了execute(),讓Receiver對象實現(xiàn)一個具體的命令。
Receiver:也就是命令的執(zhí)行對象,ConcreteCommand將會調(diào)用它
Invoke類:調(diào)用者,其有Command對象,在setCommand(command)方法中傳入一個具體的concreteCommand對象,設(shè)置具體的命令;其還有另外一個方法,用于調(diào)用concreteCommand對象的execute()方法
例子:遙控器開燈
應(yīng)用:隊列請求、日志請求
7、備忘錄模式
8、狀態(tài)模式
9、訪問者模式
10、中介者模式
11、解釋器模式