設計模式的三種類型
- 建立型模式:單例模式、工廠模式、抽象工廠模式、建造者模式、原型模式。
- 結構型模式:擴充卡模式、裝飾者模式、代理模式、橋接模式、組合模式、外觀模式、享元模式。
- 行為型模式:觀察者模式、政策模式、模版方法模式、指令模式、疊代器模式、中介者模式、備忘錄模式、解釋器模式、狀态模式、職責鍊模式、通路者模式。
常用設計模式
單例模式(Singleton Pattern)(最常問的設計模式)
單例模式隻允許建立一個對象,是以節省記憶體,加快對象通路速度,是以對象需要被公用的場合适合使用,如多個子產品使用同一個資料源連接配接對象等等。
使用場景:
- 要求生成唯一序列号的環境;
- 在整個項目中需要一個共享通路點或共享資料,例如一個Web頁面上的計數器,可以不用把每次重新整理都記錄到資料庫中,使用單例模式保持計數器的值,并確定是線程安全的;
- 建立一個對象需要消耗的資源過多,如要通路IO和資料庫等資源;
- 需要定義大量的靜态常量和靜态方法(如工具類)的環境,可以采用單例模式(當然,也可以直接聲明為static的方式)
實作方式:
餓漢式
public class Singleton {
private static Singleton instance=new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
缺點:如果我們在Singleton類裡面寫一個靜态的方法不需要建立執行個體,它仍然會早早的建立一次執行個體。沒有lazy loading的效果,進而降低記憶體的使用率。
懶漢式(改進版)
public class Singleton {
private static volatile Singleton instance;
private Singleton(){}
public static Singleton getInstance() {
if (instance != null) {
return instance;
}
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
return instance;
}
}
優點:适用于多線程,隻有 instance 初始化的時候會加鎖,加鎖很耗時,能避免就避免,可以轉移到說明 volatile 的作用
靜态内部類
public class Singleton {
private Singleton(){}
private static class SingletonHolder{
private final static Singleton instance=new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
工廠模式
用于建立對象的接口,讓子類決定執行個體化哪一個類。工廠方法使一個類的執行個體化延遲到其子類。
Product為抽象産品類負責定義産品的共性,實作對事物最抽象的定義。
Creator為抽象建立類,也就是抽象工廠,具體如何建立産品類是由具體的實作工廠ConcreteCreator完成的。
使用場景:jdbc連接配接資料庫,硬體通路,降低對象的産生和銷毀
具體工廠類
public class ConcreteCreator extends Creator{
public < T extends Product> TcreateProduct(Class<T>c){
Product product = null;
try{
product = (Product)Class.forName(c.getName()).newInstance();
}catch(Exceptione){
... //異常處理
}
return (T)product;
}
}
簡單工廠模式:一個子產品僅需要一個工廠類,沒有必要把它産生出來,使用靜态的方法。
多個工廠類:每個人種(具體的産品類)都對應了一個建立者,每個建立者獨立負責建立對應的産品對象,非常符合單一職責原則。
代替單例模式:單例模式的核心要求就是在記憶體中隻有一個對象,通過工廠方法模式也可以隻在記憶體中生産一個對象。
延遲初始化:ProductFactory負責産品類對象的建立工作,并且通過prMap變量産生一個緩存,對需要再次被重用的對象保留。
代理模式(Proxy Pattern)
為其他對象提供一種代理以控制對這個對象的通路。
- Subject抽象主題角色抽象主題類可以是抽象類也可以是接口,是一個最普通的業務類型定義,無特殊要求。
- RealSubject具體主題角色也叫做被委托角色、被代理角色。它才是冤大頭,是業務邏輯的具體執行者。
- Proxy代理主題角色也叫做委托類、代理類。它負責對真實角色的應用,把所有抽象主題類定義的方法限制委托給真實主題角色實作,并且在真實主題角色處理完畢前後做預處理和善後處理工作。
普通代理:
在該模式下,調用者隻知代理而不用知道真實的角色是誰,屏蔽了真實角色的變更對高層子產品的影響,真實的主題角色想怎麼修改就怎麼修改,對高層次的子產品沒有任何的影響,隻要你實作了接口所對應的方法,該模式非常适合對擴充性要求較高的場合。
強制代理:
強制代理的概念就是要從真實角色查找到代理角色,不允許直接通路真實角色。高層子產品隻要調用getProxy就可以通路真實角色的所有方法,它根本就不需要産生一個代理出來,代理的管理已經由真實角色自己完成。
動态代理:
根據被代理的接口生成所有的方法,也就是說給定一個接口,動态代理會宣稱“我已經實作該接口下的所有方法了”
裝飾者模式(Decorator Pattern)
動态地給一個對象添加一些額外的職責。就增加功能來說,裝飾模式相比生成子類更為靈活。
使用場景:
- 需要擴充一個類的功能,或給一個類增加附加功能。
- 需要動态地給一個對象增加功能,這些功能可以再動态地撤銷。
- 需要為一批的兄弟類進行改裝或加裝功能,當然是首選裝飾模式。
Component抽象構件
Component是一個接口或者是抽象類,就是定義我們最核心的對象,也就是最原始的對象,如上面的成績單。注意:在裝飾模式中,必然有一個最基本、最核心、最原始的接口或抽象類充當Component抽象構件。
ConcreteComponent具體構件
ConcreteComponent是最核心、最原始、最基本的接口或抽象類的實作,你要裝飾的就是它。
Decorator裝飾角色
一般是一個抽象類,做什麼用呢?實作接口或者抽象方法,它裡面可不一定有抽象的方法呀,在它的屬性裡必然有一個private變量指向Component抽象構件。
具體裝飾角色
ConcreteDecoratorA和ConcreteDecoratorB是兩個具體的裝飾類,你要把你最核心的、最原始的、最基本的東西裝飾成其他東西,上面的例子就是把一個比較平庸的成績單裝飾成家長認可的成績單。
擴充卡模式(Adapter Pattern)
将一個類的接口變換成用戶端所期待的另一種接口,進而使原本因接口不比對而無法在一起工作的兩個類能夠在一起工作。
-
Target目标角色
該角色定義把其他類轉換為何種接口,也就是我們的期望接口,例子中的IUserInfo接口就是目标角色。
-
Adaptee源角色
你想把誰轉換成目标角色,這個“誰”就是源角色,它是已經存在的、運作良好的類或對象,經過擴充卡角色的包裝,它會成為一個嶄新、靓麗的角色。
-
Adapter擴充卡
角色擴充卡模式的核心角色,其他兩個角色都是已經存在的角色,而擴充卡角色是需要建立立的,它的職責非常簡單:把源角色轉換為目标角色,怎麼轉換?通過繼承或是類關聯的方式。
觀察者模式(Observer Pattern)
定義對象間一種一對多的依賴關系,使得每當一個對象改變狀态,則所有依賴于它的對象都會得到通知并被自動更新。
使用場景:
關聯行為場景。需要注意的是,關聯行為是可拆分的,而不是“組合”關系。
事件多級觸發場景。
跨系統的消息交換場景,如消息隊列的處理機制。
注意:
廣播鍊的問題在一個觀察者模式中最多出現一個對象既是觀察者也是被觀察者,也就是說消息最多轉發一次(傳遞兩次)。
異步處理問題觀察者比較多,而且處理時間比較長,采用異步處理來考慮線程安全和隊列的問題
-
Subject被觀察者
定義被觀察者必須實作的職責,它必須能夠動态地增加、取消觀察者。它一般是抽象類或者是實作類,僅僅完成作為被觀察者必須實作的職責:管理觀察者并通知觀察者。
-
Observer觀察者
觀察者接收到消息後,即進行update(更新方法)操作,對接收到的資訊進行處理。
-
ConcreteSubject具體的被觀察者
定義被觀察者自己的業務邏輯,同時定義對哪些事件進行通知。
-
ConcreteObserver具體的觀察者
每個觀察在接收到消息後的處理反應是不同,各個觀察者有自己的處理邏輯
被觀察者(異步的話需要把 ArrayList 改為性能較低的 Vector 或 CopyOnWriteArrayList)
public abstract class Subject{
//觀察者組
private List<Observer> obsList = new ArrayList<>();
public void addObserver(Observer o){
this.obsList.add(o);
}
public void delObserver(Observer o){
this.obsList.remove(o);
}
public void notifyObservers(){
for(Observer o : obsList){
o.update();
}
}
政策模式(Strategy Pattern)
定義一組算法,将每個算法都封裝起來,并且使它們之間可以互換
使用場景:
多個類隻有在算法或行為上稍有不同的場景。
算法需要自由切換的場景。
需要屏蔽算法規則的場景。
-
Context封裝角色
它也叫做上下文角色,起承上啟下封裝作用,屏蔽高層子產品對政策、算法的直接通路,封裝可能存在的變化。
-
Strategy抽象政策角色
政策、算法家族的抽象,通常為接口,定義每個政策或算法必須具有的方法和屬性。各位看官可能要問了,類圖中的AlgorithmInterface是什麼意思,嘿嘿,algorithm是“運算法則”的意思,結合起來意思就明白了吧。
-
ConcreteStrategy具體政策角色(多個)
實作抽象政策中的操作,該類含有具體的算法。
擴充:
政策枚舉
濃縮了政策模式的枚舉
受枚舉類型的限制,每個枚舉項都是public、final、static的,擴充性受到了一定的限制,是以在系統開發中,政策枚舉一般擔當不經常發生變化的角色。
緻命缺點:
所有的政策都需要暴露出去,由用戶端決定使用哪一個政策。
public enum Calculator {
//加法運算
ADD("+"){
public int exec(int a , int b){return a + b ;}
},
//減法運算
SUB("-"){
public int exec(int a , int b){return a - b ;}
};
String value = "";
//定義成員值類型
public Calculator(String value){
this.value = value;
}
//擷取枚舉成員的值
public String getValue(){
return value;
}
//聲明抽象方法
public abstract int exec(int a , int b);
}