提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔
文章目錄
- 前言
- 1.裝飾器模式
- 1.1概念
- 1.2作用
- 1.3應用場景
- 1.4特點
- 1.5類與對象關系
- 1.6實現
- 2責任鏈模式
- 2.1概念
- 2.2作用
- 2.3應用場景
- 2.4特點
- 2.5類與對象關系
- 2.6實現
- 3.對比
- 總結
前言
裝飾器模式和設計模式同為GoF23中設計模式之一,兩者在結構上有相似之處,本文章用來學習兩個設計模式,并進行對比。
1.裝飾器模式
1.1概念
如果我們想要為一個已經寫好的類增加新功能,在不修改該類源碼的情況下,我們有以下選擇:
- 創建該類的子類,并用該子類調用父類方法,并額外添加其他功能
- 創建一個新的類,引用已有類的對象,調用原有方法并添加其他功能
這里第二種實現思路就是我們現在說的裝飾器模式。
1.2作用
為一個已有的類增加新的功能。
1.3應用場景
- 需要動態地給對象添加職責時:當你需要給某個對象添加職責,但又不想修改其類定義時,可以使用裝飾器模式。
- 需要靈活組合多個職責時:當你有多個職責需要組合,并且這些職責的排列組合可能會變化時,裝飾器模式是一個很好的選擇。
- 需要保持類的單一職責原則時:當你想保持類的單一職責原則,但又需要給類添加額外的職責時,可以使用裝飾器模式將這些職責分離到裝飾器中
1.4特點
- 動態擴展:裝飾器模式能夠在運行時動態地給對象添加職責,而無需修改類的定義。
- 靈活性:通過組合的方式而不是繼承來擴展功能,這使得裝飾器模式比繼承更加靈活。
- 遵循開閉原則:裝飾器模式可以在不修改現有代碼的情況下添加新的功能,符合開閉原則(對擴展開放,對修改關閉)。
- 裝飾器與被裝飾對象擁有相同的接口:這使得裝飾器可以透明地替代被裝飾對象
1.5類與對象關系
- 組件接口:對應上圖Component,用來規定被裝飾對象和裝飾器應該有哪些功能(或者說原組件中哪些功能是可以裝飾的)
- 組件類:對應上圖ConcreteComponent,是被裝飾對象
- 抽象裝飾器:對應上圖Decorator,是一個接口,因為我們會有多個不同的具體裝飾器,所以需要使用一個抽象裝飾器接口來指定具體裝飾器應該有哪些功能
- 具體裝飾器:是我們真正的額外功能編寫的地方,因為實現了抽象裝飾器所以擁有與被裝飾對象相同但更強大的功能,可以在使用時進行替換。
1.6實現
// 定義一個接口,規定哪些方法可以被裝飾
interface Component {void operation();
}// 具體組件類,實現了Component接口
class ConcreteComponent implements Component {@Overridepublic void operation() {System.out.println("ConcreteComponent operation");}
}// 抽象裝飾器類,持有一個Component對象,并實現了Component接口
abstract class Decorator implements Component {// 該對象存儲原對象或者被其他裝飾器裝飾過的對象// 因為可以是其他裝飾器裝飾過的對象,所以才實現裝飾器的疊加,是動態添加功能的關鍵protected Component component;public Decorator(Component component) {this.component = component;}@Overridepublic void operation() {component.operation();}
}// 具體裝飾器類A,增加了額外的行為
class ConcreteDecoratorA extends Decorator {public ConcreteDecoratorA(Component component) {super(component);}@Overridepublic void operation() {super.operation();addedBehavior();}private void addedBehavior() {System.out.println("ConcreteDecoratorA added behavior");}
}// 具體裝飾器類B,增加了額外的行為
class ConcreteDecoratorB extends Decorator {public ConcreteDecoratorB(Component component) {super(component);}@Overridepublic void operation() {addedBehavior();super.operation();}private void addedBehavior() {System.out.println("ConcreteDecoratorB added behavior");}
}// 客戶端代碼
public class DecoratorPatternDemo {public static void main(String[] args) {Component component = new ConcreteComponent();// 使用裝飾器A裝飾Component decoratorA = new ConcreteDecoratorA(component);// 使用裝飾器B裝飾裝飾器AComponent decoratorB = new ConcreteDecoratorB(decoratorA);// 執行操作,將展示所有組件和裝飾器的行為decoratorB.operation();}
}
2責任鏈模式
2.1概念
責任鏈模式是一種行為設計模式,它允許你將請求沿著處理者鏈進行傳遞。每個處理者可以對請求進行處理,或者將請求傳遞給鏈中的下一個處理者。這使得你可以在不明確具體接收者的情況下,向多個對象發送請求。
2.2作用
- 解耦請求與處理:請求者只要向鏈頭發送一次請求,而不用關心具體由誰處理。
- 可以動態管理處理類:可以按需添加或刪除處理類。
2.3應用場景
- 多個對象有機會處理請求:當請求可以在多個對象之間傳遞,并且每個對象都有可能處理它時。
- 請求處理順序可變:當請求的處理順序不固定,或者你想在不修改代碼的情況下改變處理順序時。
- 解耦請求發送者和處理者:當你想解耦請求發送者和處理者之間的依賴關系時。
2.4特點
- 鏈式傳遞:請求在多個處理者之間傳遞,直到有一個處理者處理它或鏈結束。
- 解耦請求發送者和接收者:發送者不需要知道哪個具體的處理者會處理請求,它只需要將請求發送到鏈的頭部即可。
- 增強靈活性:你可以通過動態地添加或刪除處理者來改變鏈的結構,從而改變請求的處理流程。
2.5類與對象關系
責任鏈模式中我們有以下角色:
- 抽象處理者(Handler)角色:聲明“處理”方法,以及一個“設置下一處理器”的方法
- 具體處理者(Concrete Handler)角色:實現了抽象處理者接口,并包含處理請求的邏輯。如果它不能處理請求,它會將請求傳遞給鏈中的下一個處理者。
2.6實現
// 抽象處理者接口
abstract class Handler {protected Handler nextHandler;// 設置下一個處理者public void setNextHandler(Handler nextHandler) {this.nextHandler = nextHandler;}// 處理請求的方法,由具體處理者實現public abstract void handleRequest(String request);
}// 具體處理者類A
class ConcreteHandlerA extends Handler {@Overridepublic void handleRequest(String request) {if ("A".equals(request)) {System.out.println("ConcreteHandlerA handled request: " + request);} else {if (nextHandler != null) {nextHandler.handleRequest(request);}}}
}// 具體處理者類B
class ConcreteHandlerB extends Handler {@Overridepublic void handleRequest(String request) {if ("B".equals(request)) {System.out.println("ConcreteHandlerB handled request: " + request);} else {if (nextHandler != null) {nextHandler.handleRequest(request);}}}
}// 客戶端代碼
public class ChainOfResponsibilityDemo {public static void main(String[] args) {// 創建處理者對象Handler handlerA = new ConcreteHandlerA();Handler handlerB = new ConcreteHandlerB();// 構建處理者鏈handlerA.setNextHandler(handlerB);// 創建并發送請求String[] requests = {"A", "B", "C"};for (String request : requests) {handlerA.handleRequest(request); // 請求從handlerA開始傳遞}}
}
3.對比
- 首先,鏈式設計最重要的一點是——一個節點中要存儲相鄰節點的信息,這一點在上述兩種設計模式中都有體現。這里要先清楚各自具體存儲的是什么。
- 裝飾器模式存儲的是原組件或被修飾過的組件,這說明在該種模式下各個裝飾器的作用是可以疊加的
- 責任鏈模式存儲的是下一個處理節點,這里各個處理器效果并不會疊加
- 其次,各個節點應該有同樣的任務。這兩種模式中不論是各個裝飾器,還是各個處理器,其實都有同樣的任務。但是兩個模式在具體實現時有區別,這也是裝飾器模式可疊加而責任鏈模式不可疊加的原因。
- 裝飾器中的方法邏輯是——上一節點處理邏輯"及"本節點處理邏輯
- 責任鏈中的方法邏輯是——本節點處理邏輯"或"下節點處理邏輯
總結
本文章比較了裝飾器模式和責任鏈模式,因為兩者在結構上十分相似都使用了鏈式設計,所以容易混淆,這里需要重點理解兩者在處理方法中的實現邏輯的不同,裝飾器是"且",責任鏈是"或"。