裝飾者模式:
動态的給對象添加一些額外的屬性或行為。相比于使用繼承,裝飾者模式更加靈活。
UML圖:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5yM5QTZiRjY4EWOxQmM3UmYlRjZzETY4EmZ2MjY0MGOi9CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
一般來說裝飾者模式有下面幾個參與者:
- Component:裝飾者和被裝飾者共同的父類,是一個接口或者抽象類,用來定義基本行為
- ConcreteComponent:定義具體對象,即被裝飾者
- Decorator:抽象裝飾者,繼承自Component,從外類來擴充ConcreteComponent。對于ConcreteComponent來說,不需要知道Decorator的存在,Decorator是一個接口或抽象類
- ConcreteDecorator:具體裝飾者,用于擴充ConcreteComponent
注:裝飾者和被裝飾者對象有相同的超類型,因為裝飾者和被裝飾者必須是一樣的類型,這裡利用繼承是為了達到類型比對,而不是利用繼承獲得行為。
利用繼承設計子類,隻能在編譯時靜态決定,并且所有子類都會繼承相同的行為;利用組合的做法擴充對象,就可以在運作時動态的進行擴充。裝飾者模式遵循開放-關閉原則:類應該對擴充開放,對修改關閉。利用裝飾者,我們可以實作新的裝飾者增加新的行為而不用修改現有代碼,而如果單純依賴繼承,每當需要新行為時,還得修改現有的代碼。
執行個體:
假設一家甜品店,出售蛋糕,除了蛋糕外,還可以在蛋糕上布置水果,蠟燭等,但是水果和蠟燭需要額外收費,假設一個蛋糕的價格是66元,水果和蠟燭分别需要額外付10元,那麼怎麼樣來動态的計算價格呢?例子所貼代碼已上傳Github:裝飾者模式。
首先,定義元件類,也是裝飾者和被裝飾者的超類Sweet .java:
public abstract class Sweet {
String description = "Sweet";
public String getDescription() {
return description;
}
public abstract double cost();
}
定義被裝飾者蛋糕類,Cake .java:
public class Cake extends Sweet {
@Override
public String getDescription() {
return "一個蛋糕";
}
@Override
public double cost() {
return 66;
}
}
定義抽象裝飾者類Decorator.java:
public abstract class Decorator extends Sweet {
public abstract String getDescription();
}
定義具體裝飾者水果類,FruitDecorator.java:
public class FruitDecorator extends Decorator {
Sweet sweet;
public FruitDecorator(Sweet sweet) {
this.sweet = sweet;
}
@Override
public String getDescription() {
return sweet.getDescription() + ",水果";
}
@Override
public double cost() {
return sweet.cost() + 10;
}
}
定義具體裝飾者蠟燭類,CandleDecorator.java:
public class CandleDecorator extends Decorator {
Sweet sweet;
public CandleDecorator(Sweet sweet) {
this.sweet = sweet;
}
@Override
public String getDescription() {
return sweet.getDescription() + ",蠟燭";
}
@Override
public double cost() {
return sweet.cost() + 10;
}
}
最後根據不同的選擇來結算價格:
Cake cake = new Cake();
MyLog.e(TAG, cake.getDescription() + ",總共花費" + cake.cost());
FruitDecorator fruitDecorator = new FruitDecorator(cake);
MyLog.e(TAG, fruitDecorator.getDescription() + ",總共花費" + fruitDecorator.cost());
CandleDecorator candleDecorator = new CandleDecorator(fruitDecorator);
MyLog.e(TAG, candleDecorator.getDescription() + ",總共花費" + candleDecorator.cost());
完整代碼位址已上傳Github:裝飾者模式。
執行結果:
04-16 01:30: E/DesignModeActivity: 一個蛋糕,總共花費66.0元
04-16 01:30: E/DesignModeActivity: 一個蛋糕,水果,總共花費76.0元
04-16 01:30: E/DesignModeActivity: 一個蛋糕,水果,蠟燭,總共花費86.0元
可見,裝飾者模式可以非常靈活地動态地給被裝飾者添加新行為,它的缺點也顯現出來了,那就是必須管理好更多的對象,但是,裝飾者模式可以和工廠模式或生成器這樣的模式一塊使用來避免這個問題。
PS:我們使用java.IO類時類似于下面的這種寫法:
new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream( "io.txt" )));
java.IO類用到的也是裝飾者模式!是不是一下清楚了好多~
總結:
1、裝飾者和被裝飾者對象有相同的超類型,是以在任何需要原始對象(被裝飾者)的場合,都可以用裝飾過得對象代替原始對象。
2、可以用一個或多個裝飾者包裝一個對象(被裝飾者)
3、裝飾者可以在所委托的裝飾者行為之前或之後加上自己的行為,以達到特定的目的
4、被裝飾者可以在任何時候被裝飾,是以可以在運作時動态地、不限量地用你喜歡的裝飾者來裝飾對象。
5、裝飾者會導緻出現很多小對象,如果過度使用,會讓程式變得複雜。