1. 程式人生 > 其它 >設計模式系列9-裝飾者模式

設計模式系列9-裝飾者模式

裝飾者模式(Decorator Pattern)是指在不改變原有物件的基礎之上,將功能附加到對 象上,提供了比繼承更有彈性的替代方案(擴充套件原有物件的功能),屬於結構型模式

應用場景

  1. 用於擴充套件一個類的功能或給一個類新增附加職責。
  2. 動態的給一個物件新增功能,這些功能可以再動態的撤銷。

案例

煎餅果子可以加蛋加香腸, 每位顧客的需求都不一樣

煎餅抽象類

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 事務相關的快取,都是採用裝飾者模式

裝飾者模式的優缺點

  • 優點:
  1. 裝飾者是繼承的有力補充,比繼承靈活,不改變原有物件的情況下動態地給一個物件 擴充套件功能,即插即用。
  2. 通過使用不同裝飾類以及這些裝飾類的排列組合,可以實現不同效果。
  3. 裝飾者完全遵守開閉原則。
  • 缺點:
  1. 會出現更多的程式碼,更多的類,增加程式複雜性。
  2. 動態裝飾時,多層裝飾時會更復雜。