設計模式系列9-裝飾者模式
阿新 • • 發佈:2021-09-27
裝飾者模式(Decorator Pattern)
是指在不改變原有物件的基礎之上,將功能附加到對 象上,提供了比繼承更有彈性的替代方案(擴充套件原有物件的功能),屬於結構型模式
應用場景
- 用於擴充套件一個類的功能或給一個類新增附加職責。
- 動態的給一個物件新增功能,這些功能可以再動態的撤銷。
案例
煎餅果子可以加蛋加香腸, 每位顧客的需求都不一樣
煎餅抽象類
public abstract class Battercake {
protected abstract String getMsg();
protected abstract int getPrice();
}
基礎煎餅類
public class BaseBattercake extends Battercake {
protected String getMsg(){
return "煎餅";
}
public int getPrice(){
return 5;
}
}
煎餅裝飾器
public abstract class BattercakeDecorator extends Battercake { //靜態代理,委派 private Battercake battercake; public BattercakeDecorator(Battercake battercake) { this.battercake = battercake; } protected abstract void doSomething(); @Override protected String getMsg() { return this.battercake.getMsg(); } @Override protected int getPrice() { return this.battercake.getPrice(); } }
雞蛋裝飾
public class EggDecorator extends BattercakeDecorator { public EggDecorator(Battercake battercake) { super(battercake); } protected void doSomething() { } @Override protected String getMsg() { return super.getMsg() + "+1個雞蛋"; } @Override protected int getPrice() { return super.getPrice() + 1; } }
香腸裝飾
public class SausageDecorator extends BattercakeDecorator {
public SausageDecorator(Battercake battercake) {
super(battercake);
}
protected void doSomething() {
}
@Override
protected String getMsg() {
return super.getMsg() + "+1根香腸";
}
@Override
protected int getPrice() {
return super.getPrice() + 2;
}
}
測試
public static void main(String[] args) {
Battercake battercake = new BaseBattercake();
System.out.println(battercake.getMsg() + battercake.getPrice());
battercake = new EggDecorator(battercake);
System.out.println(battercake.getMsg() + battercake.getPrice());
battercake = new SausageDecorator(battercake);
System.out.println(battercake.getMsg() + battercake.getPrice());
battercake = new EggDecorator(battercake);
System.out.println(battercake.getMsg() + battercake.getPrice());
}
裝飾者模式和介面卡模式對比
裝飾者和介面卡模式都是包裝模式(Wrapper Pattern),裝飾者也是一種特殊的代理模式。
裝飾者模式 | 介面卡模式 | |
---|---|---|
形式 | 是一種非常特別的介面卡模式 | 沒有層級關係,裝飾器模式有層級關係 |
定義 | 裝飾者和被裝飾者都實現同一個接 口主要目的是為了擴充套件之後依舊保 留 OOP 關係 | 介面卡和被適配者沒有必然的聯絡,通常是採用繼承或代理的形式進行包裝 |
關係 | 滿足 is-a 的關係 | 滿足 has-a 的關係 |
功能 | 注重覆蓋、擴充套件 | 注重相容、轉換 |
設計 | 前置考慮 | 後置考慮 |
原始碼體現
Java
裝飾器模式在原始碼中也應用得非常多,在 JDK 中體現最明顯的類就是 IO 相關的類
Spring
在 Spring 中的 TransactionAwareCacheDecorator
類,這 個類主要是用來處理事務快取的
public class TransactionAwareCacheDecorator implements Cache {
private final Cache targetCache;
public TransactionAwareCacheDecorator(Cache targetCache) {
Assert.notNull(targetCache, "Target Cache must not be null");
this.targetCache = targetCache;
}
public Cache getTargetCache() {
return this.targetCache;
}
}
TransactionAwareCacheDecorator 就是對 Cache 的一個包裝
SpringMVC
再來看一個 MVC 中的 裝飾者模式 HttpHeadResponseDecorator
類
public class HttpHeadResponseDecorator extends ServerHttpResponseDecorator {
public HttpHeadResponseDecorator(ServerHttpResponse delegate) {
super(delegate);
}
}
MyBatis
MyBatis 中的一段處理快取的設計 org.apache.ibatis.cache.Cache 類
從名字上來看其實更容易理解了。比如 FifoCache 先入先出演算法的快取;LruCache 最近 最少使用的快取;TransactionlCache 事務相關的快取,都是採用裝飾者模式
裝飾者模式的優缺點
- 優點:
- 裝飾者是繼承的有力補充,比繼承靈活,不改變原有物件的情況下動態地給一個物件 擴充套件功能,即插即用。
- 通過使用不同裝飾類以及這些裝飾類的排列組合,可以實現不同效果。
- 裝飾者完全遵守開閉原則。
- 缺點:
- 會出現更多的程式碼,更多的類,增加程式複雜性。
- 動態裝飾時,多層裝飾時會更復雜。