文章目錄
- 設計模式概述
- 設計模式的定義:
- 設計模式的分類:
- 常見的設計模式:
- 面向物件設計原則
- 創建型設計模式(重點)
- 簡單工廠模式
- 工廠方法模式
- 抽象工廠模式
- 單例模式
- 結構性型設計模式(重點)
- 配接器模式
- 橋接模式
- 組合模式
- 外觀模式
- 代理模式
- 行為型設計模式(重點)
- 觀察者模式
- 策略模式
設計模式概述
設計模式的定義:
- 一套被反復使用的、多數人知曉的、經過分類編目的、代碼設計經驗的總結
- 目的:為了可重用代碼、讓代碼更容易被他人理解、提高代碼的可靠性
- 是一種用于對軟體系統中不斷重現的設計問題的解決方案進行檔案化的技術
- 是一種共享專家設計經驗的技術
GOF的定義: 設計模式是在特定環境下為解決某一通用軟體設計問題提供的一套定制的解決方案,該方案描述了物件和類之間的相互作用,
設計模式的基本要素:
- 模式名稱
- 問題
- 解決方案
- 效果
設計模式的分類:
根據目的分類:
- 創建型模式:主要用于創建物件
- 結構型模式:主要用于處理類或物件的組合
- 行為型模式:主要用于對描述類或物件如何互動和怎樣分配職責
根據范圍分類(模式主要是處理類之間的關系還是處理物件之間的關系):
- 類模式:處理類和子類之間的關系;這些關系通過繼承建立,是一種靜態關系
- 物件模式:處理物件間的關系;更具有動態性
常見的設計模式:
| 范圍\目的 | 創建型模式 | 結構型模式 | 行為型模式 |
|---|---|---|---|
| 類模式 | 工廠方法模式 | (類)配接器模式 | 解釋器模式、模板方法模式 |
| 物件模式 | 抽象工廠、建造者、原型、單例 | (物件)配接器、橋接、組合、裝飾、外觀、享元、代理 | 職責鏈、命令、迭代器、中介者、備忘錄、觀察者、狀態、策略、訪問者 |
面向物件設計原則
| 模式名稱 | 定義 |
|---|---|
| 單一職責原則SRP | 一個物件應該只包含單一的職責,并且該職責被完整的封裝在一個類中 |
| 開閉原則OCP | 軟體物體應當對擴展開放,都修改關閉 |
| 里氏代換原則LSP | 所有參考基類的地方必須能透明的使用其子類的物件 |
| 依賴倒轉原則DIP | 高層模塊不應該依賴底層模塊,他們都應該依賴抽象,抽線不應該依賴于細節,細節應該依賴抽象 |
| 介面隔離原則ISP | 客戶端不應該依賴那些它不需要的介面 |
| 合成復用原則CRP | 優先使用物件組合,而不是繼承來達到復用 |
| 迪米特法則LoD | 每個軟體單位對其他的單位都只有最少的知識,而對局限于那些與本單位密切相關的軟體單元 |
創建型設計模式(重點)
| 模式名稱 | 定義 |
|---|---|
| 簡單工廠模式 | 定義一個工廠類,它可以根據引數的不同回傳不同類的實體,被創建的實體通常都具有共同的父類 |
| 工廠方法模式 | 定義一個用于創建物件的介面,但是讓子類決定將哪一個類實體化,工廠方法模式讓一個類的實體化延遲到其子類 |
| 抽象工廠模式 | 提供一個創建一系列相關或相互依賴物件的介面,而無須指定它們具體的類 |
| 建造者模式 | 將一個復雜物件的構建與它的表示分離,使得同樣構建程序可以創建不同的表達 |
| 原型模式 | 使用原型實體制定待創建物件的型別,并且通過復制這個原型來創建新的物件 |
| 單例模式 | 確保一個類只有一個實體,并提供一個全域訪問點來訪問這個唯一實體 |
簡單工廠模式
簡單工廠模式結構:

- Factory(工廠角色)
- Product(抽象產品角色)
- ConcreteProduct(具體產品角色)
抽象產品類
public abstract class Product {
//所有產品類的公共業務方法
public void methodSame() {
//公共方法的實作
}
//宣告抽象業務方法
public abstract void methodDiff();
}
具體產品類
public class ConcreteProduct extends Product{
//實作業務方法
public void methodDiff() {
//業務方法的實作
}
}
工廠類
public class Factory {
//靜態工廠方法
public static Product getProduct(String arg) {
Product product = null;
if (arg.equalslgnoreCase("A")){
product = new ConcreteProductA();
//初始化設定product
}
else if (arg.equalslgnoreCase("B"")){
product = new ConcreteProductB();
//初始化設定product
}
return product;
}
}
客戶類
public class Client {
public static void main(String args[]) {
Product product;
product = Factory.getProduct("A");
//通過工廠類創建產品對
product.methodSame();
product.methodDiff();
}
}
優點:
- 實作了物件創建和使用的分離
- 客戶端無須知道所創建的具體產品類的類名,只需要知道具體產品類所對應的引數即可
- 通過引入組態檔,可以在不修改任何客戶端代碼的情況下更換和增加新的具體產品類,在一定程度上提高了系統的靈活性
缺點:
- 工廠類集中了所有產品的創建邏輯,職責過重,一旦不能正常作業,整個系統都要受到影響
- 增加系統中類的個數(引入了新的工廠類),增加了系統的復雜度和理解難度
- 系統擴展困難,一旦添加新產品不得不修改工廠邏輯
- 由于使用了靜態工廠方法,造成工廠角色無法形成基于繼承的等級結構,工廠類不能得到很好地擴展
適用環境:
- 工廠類負責創建的物件比較少,由于創建的物件較少,不會造成工廠方法中的業務邏輯太過復雜
- 客戶端只知道傳入工廠類的引數,對于如何創建物件并不關心擴展
工廠方法模式
工廠方法模式結構:

- Product(抽象產品)
- ConcreteProduct(具體產品)
- Factory(抽象工廠)
- ConcreteProduct(具體工廠)
抽象工廠類
public interface Factory {
public Product factoryMethod();
}
具體工廠類
public class ConcreteFactory implements Factory {
public Product factoryMethod() {
return new ConcreteProduct();
}
}
客戶端代碼
......
Factory factory;
factory = new ConcreteFactory();//可通過組態檔和反射機制實作Product product;
product = factory.factoryMethod();
......
優點:
- 工廠方法用來創建客戶所需要的產品,同時還向客戶隱藏了哪種具體產品類將被實體化這一細節
- 能夠讓工廠自主確定創建何種產品物件,而如何創建這個物件的細節則完全封裝在具體工廠內部
- 在系統中加入新產品時,完全符合開閉原則
缺點:
- 系統中類的個數將成對增加,在一定程度上增加了系統的復雜度,會給系統帶來一些額外的開銷
- 增加了系統的抽象性和理解難度
適用環境:
- 客戶端不知道它所需要的物件的類(客戶端不需要知道具體產品類的類名,只需要知道所對應的工廠即可,具體產品物件由具體工廠類創建)
- 抽象工廠類通過其子類來指定創建哪個物件
抽象工廠模式
概念:
- 產品等級結構:產品等級結構即產品的繼承結構
- 產品族:產品族是指由同一個工廠生產的,位于不同產品等級結構中的一組產品
- 當系統所提供的工廠生產的具體產品并不是一個簡單的物件,而是多個位于不同產品等級結構、屬于不同型別的具體產品時就可以使用抽象工廠模式
- 抽象工廠模式是所有形式的工廠模式中最為抽象和最具一般性的一種形式

工廠方法模式結構:

- AbstractFactory(抽象工廠)
- ConcreteFactory(具體工廠)
- AbstractProduct(抽象產品)
- ConcreteProduct(具體產品)
抽象工廠類
public interface AbstractFactory {
public AbstractProductA createProductA();//工廠方法一
public AbstractProductB createProductB();//工廠方法二
......
}
具體工廠類
public class ConcreteFactory1 implements AbstractFactory {
//工廠方法一
public AbstractProductA createProductA() {
return new ConcreteProductA1();
}
//工廠方法二
public AbstractProductB createProductB(){
return new ConcreteProductB1();
}
優點:
- 隔離了具體類的生成,使得客戶端并不需要知道什么被創建
- 當一個產品族中的多個物件被設計成一起作業時,它能夠保證客戶端始終只使用同一個產品族中的物件
- 增加新的產品族很方便,無須修改已有系統,符合開閉原則
缺點:
- 增加新的產品等級結構麻煩,需要對原有系統進行較大的修改,甚至需要修改抽象層代碼,這顯然會帶來較大的不便,違背了開閉原則
適用環境:
- 一個系統不應當依賴于產品類實體如何被創建、組合和表達的細節
- 系統中有多于一個的產品族,但每次只使用其中某一產品族
- 屬于同一個產品族的產品將在一起使用,這一約束必須在系統的設計中體現出來
- 產品等級結構穩定,在設計完成之后不會向系統中增加新的產品等級結構或者洗掉已有的產品等級結構
單例模式
單例模式結構:

- Singleton(單例)
/*要求:
私有建構式
靜態私有成員變數(自身型別)
靜態公有的工廠方法
*/
public class Singleton {
private static singleton instance=null;//靜態私有成員變數
//私有建構式
private Singleton() {}
// 靜態公有工廠方法,回傳唯一實體
public static singleton getlnstance() {
if( instance==null)
instance=new Singleton();return instance;
}
}
餓漢式單例(Eager Singleton)

public class EagerSingleton {
private static final EagerSingleton instance = new EagerSingletonO);
private EagerSingleton( {}
public static EagerSingleton getInstance(){
return instance;
}
}
懶漢式單例(Lazy Singleton)

//延時加載(Lazy Load)基礎版
public class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton() { }
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
-------------------------------------------------------
改進版--鎖方法
public class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton() { }
synchronized public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
-------------------------------------------------------
鎖代碼段
……
public static LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) {
instance = new LazySingleton();
}
}
return instance;
}
……
-------------------------------------------------------
雙重檢查鎖定
public class LazySingleton {
private volatile static LazySingleton instance = null;
private LazySingleton() { }
public static LazySingleton getInstance() {
//第一重判斷
if (instance == null) {
//鎖定代碼塊
synchronized (LazySingleton.class) {
//第二重判斷
if (instance == null) {
instance = new LazySingleton(); //創建單例實體
}
}
}
return instance;
}
}
- 餓漢式單例類:無須考慮多個執行緒同時訪問的問題;呼叫速度和反應時間優于懶漢式單例;資源利用效率不及懶漢式單例;系統加載時間可能會比較長
- 懶漢式單例類:實作了延遲加載;必須處理好多個執行緒同時訪問的問題;需通過雙重檢查鎖定等機制進行控制,將導致系統性能受到一定影響
優點:
- 提供了對唯一實體的受控訪問
- 可以節約系統資源,提高系統的性能
- 允許可變數目的實體(多例類)
缺點:
- 擴展困難(缺少抽象層)
- 單例類的職責過重
- 由于自動垃圾回識訓制,可能會導致共享的單例物件的狀態丟失
適用環境:
- 系統只需要一個實體物件,或者因為資源消耗太大而只允許創建一個物件
- 客戶呼叫類的單個實體只允許使用一個公共訪問點,除了該公共訪問點,不能通過其他途徑訪問該實體
結構性型設計模式(重點)
分類:
-
類結構型模式:關心類的組合,由多個類組合成一個更大的系統,在類結構型模式中一般只存在繼承關系和實作關系
-
物件結構型模式:關心類與物件的組合,通過關聯關系,在一個類中定義另一個類的實體物件,然后通過該物件呼叫相應的方法
| 模式名稱 | 定義 |
|---|---|
| 配接器模式 | 將一個類的介面轉換成客戶希望的另一個介面,配接器模式讓那些介面不兼容的可以一起作業 |
| 橋接模式 | 將抽象部分與它實作部分解耦,使得兩者都能夠獨立變化 |
| 組合模式 | 組合多個物件形成樹形結構,以表示具有部分-整體關系的層次結構,組合模式讓客戶端可以統一對待單個物件和組合物件 |
| 裝飾模式 | 動態的給一個物件增加一些額外的職責,就擴展功能而言,裝飾模式提供了一種比使用子類更加靈活的替代方案 |
| 外觀模式 | 為子系統中的一組介面提供一個統一的入口,外觀模式定義了一個高層介面,這個介面使得這個子系統更加容易使用 |
| 享元模式 | 運用共享技術有效地支持大量細粒度物件的復用 |
| 代理模式 | 給某一個物件提供一個代理或占位符,并由代理物件來控制對原物件的訪問 |
配接器模式
配接器模式結構(類配接器):

配接器模式結構(物件配接器):

- Target(目標抽象類)
- Adapter(配接器類)
- Adaptee(適配者類)
類配接器
public class Adapter extends Adaptee implements Target {
public void request() {
super.specificRequest();
}
}
物件配接器
public class Adapter extends Target {
private Adaptee adaptee;//維持一個對適配者物件的參考
public Adapter(Adaptee adaptee) {
this.adaptee=adaptee;
}
public void request() {
adaptee.specificRequest();
//轉發呼叫
}
}
優點:
- 將目標類和適配者類解耦,通過引入一個配接器類來重用現有的適配者類,無須修改原有結構
- 增加了類的透明性和復用性,提高了適配者的復用性,同一個適配者類可以在多個不同的系統中復用
- 靈活性和擴展性非常好
- 類配接器模式:置換一些適配者的方法很方便
- 物件配接器模式:可以把多個不同的適配者適配到同一個目標,還可以適配一個適配者的子類
缺點:
1、類配接器模式:
- 一次最多只能適配一個適配者類,不能同時適配多個適配者·
- 配者類不能為最終類
- 目標抽象類只能為介面,不能為類
2、物件配接器模式:在配接器中置換適配者類的某些方法比較麻煩
適用環境:
- 系統需要使用一些現有的類(適配者),而這些類的介面不符合系統的需要,甚至沒有這些類的源代碼
- 創建一個可以重復使用的類(目標類/適配者),用于和一些彼此之間沒有太大關聯的類,包括一些可能在將來引進的類一起作業
橋接模式
橋接模式結構:

- Abstraction(抽象類)
- RefineAbstraction(擴充抽象類)
- Implementor(實作類介面)
- ConcreteImplementor(具體實作類)
類介面
public interface Implementor {
public void operationlmpl();
}
具體實作類
public class Concretelmplementor implements Implementor {
public void operationlmpl() {
//具體業務方法的實作
}
}
抽象類
public abstract class Abstraction {
protected lmplementor impl;//定義實作類介面物件
public void setlmpl(Implementor impl){
this.impl=impl;
}
public abstract void operation();//宣告抽象業務方法
}
擴充抽象類(細化抽象類)
public class RefinedAbstraction extends Abstraction {
public void operation() {
//業務代碼
impl.operationlmpl();//呼叫實作類的方法業務代碼
}
橋接模式與配接器模式的聯用
- 橋接模式:用于系統的初步設計,對于存在兩個獨立變化維度的類可以將其分為抽象化和實作化兩個角色,使它們可以分別進行變化
- 配接器模式:當發現系統與已有類無法協同作業時

優點:
- 分離抽象介面及其實作部分
- 可以取代多層繼承方案,極大地減少了子類的個數
- 提高了系統的可擴展性,在兩個變化維度中任意擴展一個維度,不需要修改原有系統,符合開閉原則
缺點:
- 會增加系統的理解與設計難度,由于關聯關系建立在抽象層,要求開發者開始就針對抽象層進行設計與編程
- 正確識別出系統中兩個獨立變化的維度并不是一件容易的事情
適用環境:
- 需要在抽象化和具體化之間增加更多的靈活性,避免在兩個層次之間建立靜態的繼承關系
- 抽象部分和實作部分可以以繼承的方式獨立擴展而互不影響
- 一個類存在兩個(或多個)獨立變化的維度,且這兩個(或多個)維度都需要獨立地進行擴展
- 不希望使用繼承或因為多層繼承導致系統類的個數急劇增加的系統
組合模式
組合模式結構:

- Component(抽象構件)
- Leaf(葉子構件)
- Composite(容器構件)
抽象構件角色
public abstract class Component {
public abstract void add(Component c);//增加成員
public abstract void remove(Component c);//洗掉成員
public abstract Component getChild(int i);//獲取成員
public abstract void operation();//業務方法
}
葉子構件角色
public class Leaf extends Component {
public void add(component c) {//例外處理或錯誤提示
}
public void remove(Component c) {//例外處理或錯誤提示
}
public component getChild(int i) {//例外處理或錯誤提示
return null;
}
public void operation() {
//葉子構件具體業務方法的實作
}
容器構件角色
public class Composite extends Component {
private ArrayList<Component> list = new ArrayList<Component>();
public void add(Component c){
list.add(c);
}
public void remove(Component c){
list.remove(c);
}
public Component getChild(int i) {
return (Component)list. get(i);
}
public void operation(){
//容器構件具體業務方法的實作,將遞回呼叫成員構件的業務方法
for(Object obj:list) {
((component)obj).operation();
}
}
}
優點:
- 可以清楚地定義分層次的復雜物件,表示物件的全部或部分層次,讓客戶端忽略了層次的差異,方便對整個層次結構進行控制
- 客戶端可以一致地使用一個組合結構或其中單個物件,不必關心處理的是單個物件還是整個組合結構,簡化了客戶端代碼
- 增加新的容器構件和葉子構件都很方便,符合開閉原則
- 為樹形結構的面向物件實作提供了一種靈活的解決方案
缺點:
- 在增加新構件時很難對容器中的構件型別進行限制
適用環境:
- 在具有整體和部分的層次結構中,希望通過一種方式忽略整體與部分的差異,客戶端可以一致地對待它們
- 在一個使用面向物件語言開發的系統中需要處理一個樹形結構
- 在一個系統中能夠分離出葉子物件和容器物件,而且它們的型別不固定,需要增加一些新的型別
外觀模式
外觀模式結構:

- Facade(外觀角色)
- SubSystem(子系統角色)
子系統類
public class SubSystemA {
public void methodA() {
//業務實作代碼
}
}
public class SubSystemB {
public void methodB() {
//業務實作代碼
}
}
public class SubSystemC {
public void methodC(){
//業務實作代碼
}
}
外觀類
public class Facade {
private SubSystemA obj1 = new SubSystemA();
private SubSystemB obj2 = new SubSystemB();
private SubSystemC obj3 = new SubSystemc();
public void method() {
obj1.methodA();
obj2.methodB();
obj3.methodC();
}
}
客戶類
public class Client {
public static void main(String args[]){
Facade facade = new Facade();
facade.method();
}
}
外觀模式與單例模式聯用

優點:
- 對客戶端屏蔽了子系統組件,減少了客戶端所需處理的物件數目,并使得子系統使用起來更加容易
- 現了子系統與客戶端之間的松耦合關系,這使得子系統的變化不會影響到呼叫它的客戶端,只需要調整外觀類即可
- 子系統的內部變化不會影響到外觀物件,一個子系統的修改對其他子系統也沒有任何影響
缺點:
- 不能很好地限制客戶端直接使用子系統類,如果對客戶端訪問子系統類做太多的限制則減少了可變性和靈活性
- 如果設計不當,增加新的子系統可能需要修改外觀類的源代碼,違背了開閉原則
適用環境:
- 要為訪問一系列復雜的子系統提供一個簡單入口
- 客戶端程式與多個子系統之間存在很大的依賴性
- 在層次化結構中,可以使用外觀模式的定義系統中每一層的入口,層與層之間不直接產生聯系,而是通過外觀類建立聯系,降低層之間的耦合度
代理模式
代理模式結構:

- Subject(抽象主題角色)
- Proxy(代理主題角色)
- RealSubject(真實主題角色)
抽象主題類
public abstract class Subject {
public abstract void request();
}
真實主題類
public class RealSubject extends Subject{
public void request() {
//業務方法具體實作代碼
}
}
代理類
public class Proxy extends Subject {
private RealSubject realSubject = new RealSubject();
//維持一個對真實主題 物件的參考
public void preRequest() {
……
}
public void request(){
preRequest();
realSubject.request();
//呼叫真實主題物件的方法
postRequest();
}
public void postRequest() {
……
}
}
常見的代理模式:
- 遠程代理(Remote Proxy):為一個位于不同的地址空間的物件提供一個本地的代理物件,這個不同的地址空間可以在同一臺主機中,也可以在另一臺主機中,遠程代理又稱為大使(Ambassador)
- 虛擬代理(Virtual Proxy):如果需要創建一個資源消耗較大的物件,先創建一個消耗相對較小的物件來表示,真實物件只在需要時才會被真正創建
- 保護代理(Protect Proxy):控制對一個物件的訪問,可以給不同的用戶提供不同級別的使用權限
- 緩沖代理(Cache Proxy):為某一個目標操作的結果提供臨時的存盤空間,以便多個客戶端可以共享這些結果
- 智能參考代理(Smart Reference Proxy):當一個物件被參考時,提供一些額外的操作,例如將物件被呼叫的次數記錄下來等
優點:
- 共有優點:
- 能夠協調呼叫者和被呼叫者,在一定程度上降低了系統的耦合度
- 客戶端可以針對抽象主題角色進行編程,增加和更換代理類無須修改源代碼,符合開閉原則,系統具有較好的靈活性和可擴展性
- 不同型別優點:
- 遠程代理:可以將一些消耗資源較多的物件和操作移至性能更好的計算機上,提高了系統的整體運行效率
- 虛擬代理:通過一個消耗資源較少的物件來代表一個消耗資源較多的物件,可以在一定程度上節省系統的運行開銷
- 緩沖代理:為某一個操作的結果提供臨時的快取存盤空間,以便在后續使用中能夠共享這些結果,優化系統性能,縮短執行時間
- 保護代理:可以控制對一個物件的訪問權限,為不同用戶提供不同級別的使用權限
缺點:
- 由于在客戶端和真實主題之間增加了代理物件,因此有些型別的代理模式可能會造成請求的處理速度變慢(例如保護代理)
- 實作代理模式需要額外的作業,而且有些代理模式的實作程序較為復雜(例如遠程代理)
使用環境:
- 當客戶端物件需要訪問遠程主機中的物件時可以使用遠程代理
- 當需要用一個消耗資源較少的物件來代表一個消耗資源較多的物件,從而降低系統開銷、縮短運行時間時可以使用虛擬代理
- 當需要為某一個被頻繁訪問的操作結果提供一個臨時存盤空間,以供多個客戶端共享訪問這些結果時可以使用緩沖代理
- 當需要控制對一個物件的訪問,為不同用戶提供不同級別的訪問權限時可以使用保護代理
- 當需要為一個物件的訪問(參考)提供一些額外的操作時可以使用智能參考代理
行為型設計模式(重點)
分類:
- 類行為型模式:使用繼承關系在幾個類之間分配行為,主要通過多型等方式來分配父類與子類的職責
- 物件行為型模式:使用物件的關聯關系來分配行為,主要通過物件關聯等方式來分配兩個或多個類的職責
| 模式名稱 | 定義 |
|---|---|
| 職責鏈模式 | 避免將一個請求的發送者與接收者耦合在一起,讓多個物件都有機會處理請求,將接受請求的物件連接成一條鏈,并且沿著這條鏈傳遞請求,直到有一個物件能夠處理它為止 |
| 命令模式 | 將—個請求封裝為一個物件,從而讓你可以用不同的請求對客戶進行引數化,對請求排隊或者記錄請求日志,以及支持可撤銷的操作, |
| 解釋器模式 | 給定一個語言,定義它的文法的一種表示,并定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子, |
| 迭代器模式 | 提供—種方法順序訪問一個聚合物件中的各個元素,且不用暴露該物件的內部表示, |
| 中介者模式 | 定義一個物件來封裝一系列物件的互動,中介者模式使各物件之間不需要顯式地相互參考,從而使其耦合松散,而且讓你可以獨立地改變它們之間的互動, |
| 備忘錄模式 | 在不破壞封裝的前提下,捕獲一個物件的內部狀態,并在該物件之外保存這個狀態,這樣可以在以后將物件恢復到原先保存的狀態, |
| 觀察者模式 | 定義物件之間的一種—對多依賴關系,使得每當一個物件狀態發生改變時,其相關依賴物件都得到通知并被自動更新, |
| 狀態模式 | 允許一個物件在其內部狀態改變時改變它的行為,物件看起來似乎修改了它的類, |
| 策略模式 | 定義一系列演算法,將每一個演算法封裝起來,并讓它們可以相互替換,策略模式讓演算法可以獨立于使用它的客戶變化, |
| 模板方法模式 | 定義一個操作中演算法的框架,而將一些步驟延遲到子類中,模板方法模式使得子類不改變一個演算法的結構即可重定義該演算法的某些特定步驟, |
| 訪問者模式 | 表示一個作用于某物件結構中的各個元素的操作,訪問者模式讓你可以在不改變各元素的類的前提下定義作用于這些元素的新操作, |
觀察者模式
觀察者模式結構:

- Subject(目標)
- ConcreteSubject(具體目標)
- Observer(觀察者)
- ConcreteObserver(具體觀察者)
抽象目標類
import java.util.*;
public abstract class Subject {
//定義一個觀察者集合用于存盤所有觀察者物件
protected ArrayList observers<Observer> = newArrayList();
//注冊方法,用于向觀察者集合中增加一個觀察者
public void attach(Observer observer){
observers.add(observer);
}
//注銷方法,用于在觀察者集合中洗掉一個觀察者
public void detach(Observer observer){
observers.remove(observer);
}
//宣告抽象通知方法
public abstract void notify();
}
具體目標類
public class ConcreteSubject extends Subject {
//實作通知方法
public void notify(){
//遍歷觀察者集合,呼叫每一個觀察者的回應方法
for(Object obs:observers){
((Observer)obs).update();
}
}
}
抽象觀察者
public interface Observer {
//宣告回應方法
public void update();
}
具體觀察者
public class ConcreteObserver implements Observer {
//實作回應方法
public void update() {
//具體回應代碼
}
}
客戶端代碼
……
Subject subject = new ConcreteSubject();
Observer observer = new ConcreteObserver();subject.attach(observer);ll注冊觀察者
subject.notify();
……
優點:
- 可以實作表示層和資料邏輯層的分離
- 在觀察目標和觀察者之間建立一個抽象的耦合
- 支持廣播通信,簡化了一對多系統設計的難度
- 符合開閉原則,增加新的具體觀察者無須修改原有系統代碼,在具體觀察者與觀察目標之間不存在關聯關系的情況下,增加新的觀察目標也很方便
缺點:
- 將所有的觀察者都通知到會花費很多時間
- 如果存在回圈依賴時可能導致系統崩潰
- 沒有相應的機制讓觀察者知道所觀察的目標物件是怎么發生變化的,而只是知道觀察目標發生了變化
適用環境:
- 一個抽象模型有兩個方面,其中一個方面依賴于另一個方面,將這兩個方面封裝在獨立的物件中使它們可以各自獨立地改變和復用
- 一個物件的改變將導致一個或多個其他物件發生改變,且并不知道具體有多少物件將發生改變,也不知道這些物件是誰
- 需要在系統中創建一個觸發鏈
策略模式
策略模式結構

- Context(環境類)
- Strategy(抽象策略類)
- ConcreteStrategy(具體策略類)
抽象策略類
public abstract class Strategy {
public abstract void algorithm();
//宣告抽象演算法
}
具體策略類
public class ConcreteStrategyA extends Strategy {
//演算法的具體實作
public void algorithm() {
//演算法A
}
}
環境類
public class Context {
private Strategy strategy;//維持一個對抽象策略類的參考
//注入策略物件
public void setStrategy(Strategy strategy) {
this.strategy= strategy;
}
//呼叫策略類中的演算法
public void algorithm() {
strategy.algorithm();
}
}
客戶端
……
Context context = new Context();
Strategy strategy;
strategy = new ConcreteStrategyA();
//可在運行時指定型別,通過組態檔和反射機制實作
context.setStrategy(strategy);
context.algorithm();
……
優點:
- 提供了對開閉原則的完美支持,用戶可以在不修改原有系統的基礎上選擇演算法或行為,也可以靈活地增加新的演算法或行為
- 提供了管理相關的演算法族的辦法
- 提供了一種可以替換繼承關系的辦法可以避免多重條件選擇陳述句
- 提供了一種演算法的復用機制,不同的環境類可以方便地復用策略類
缺點:
- 客戶端必須知道所有的策略類,并自行決定使用哪一個策略類
- 將造成系統產生很多具體策略類
- 無法同時在客戶端使用多個策略類
適用環境:
- 一個系統需要動態地在幾種演算法中選擇一種
- 避免使用難以維護的多重條件選擇陳述句
- 不希望客戶端知道復雜的、與演算法相關的資料結構,提高演算法的保密性與安全性
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/247203.html
標籤:其他
上一篇:簡單連接資料庫(swing)
