目錄
- 基本介紹
- 裝飾器模式
- IO體系中的裝飾器
基本介紹
裝飾器模式意圖為一個物件擴展新的功能,且不改變原有的結構,裝飾器模式屬于結構型設計模式
一般的,我們為了擴展一個類經常使用繼承方式實作,由于繼承為類引入靜態特征,并且隨著擴展功能的增多,子類會很膨脹
使用場景
- 擴展一個類的功能
- 動態增加功能,動態撤銷
假設有一家咖啡公司,姑且咱就叫怪獸咖啡吧,該咖啡公司是以擴展速度最快而聞名的咖啡公司(像瑞幸咖啡一樣),但是最近由于擴展速度太快,它們想重新設計一套訂單系統,以滿足它們現在的飲料需求,
他們最初始的設計如下:

然鵝用戶在購買咖啡時,通常會添加一些調料,例如:摩卡、豆漿、奶泡等等,怪獸咖啡并根據業務去計算相應的總價,這就要求咖啡公司在設計訂單時需要考慮這些調料的部分,然后就設計出這么一套龐雜的系統,因為奶茶種類太多,調料太多,種類*調料 = 類爆炸,實在太瘋狂了

這么設計的問題顯而易見
- 調料價格變化時,需要更改現有代碼
- 出現新的調料,需要添加新的方法,并改動超類中的
cost()方法 - 以后開發新的飲料,對于這些飲料,某些調料并不適合,但是這個設計中,子類仍需繼承那些不需要的方法
裝飾器模式
從上述的設計方案來看,這顯然并不是一個聰明的結果,因為會遇到 類爆炸、設計過于冗余,以及基類加入的新功能并不一定適用于所有子類
所以我們要考慮換一種方式,設想一下 我們能不能 以飲料為紅花,用調料作為 綠葉 裝飾它
比如,客戶想要 摩卡和奶泡 搭配黑莓咖啡(口味獨特),那么,我們怎么做呢?
- 拿黑莓咖啡(DarkRoast)作為物件
- 用摩卡(Mocha)物件裝飾它
- 用奶泡(Whip)物件裝飾它
- 呼叫 cost() 方法,并通過依賴將調料價格和摩卡價格想加


上圖詳細的介紹了,裝飾模式的總體程序

上圖為裝飾器模式的結構類圖以及各個類的作用說明
好,下面我們詳細介紹訂單系統的正確設計方案
1、我們先設計飲料組件
/**
* 創建一個飲料抽象類
*/
public abstract class Beverage {
String description = "UnKnown Beverage";
public String getDescription() {
return description;
}
public abstract Double cost();
}
2、假設目前店鋪中,有 綜合咖啡、濃縮咖啡、黑莓
public class HouseBlend extends Beverage {
public HouseBlend() {
description = "綜合咖啡";
}
@Override
public Double cost() {
return 23.2;
}
}
public class Expresso extends Beverage{
public Expresso(){
description = "濃縮咖啡";
}
@Override
public Double cost() {
return 19.9;
}
}
public class DarkRoast extends Beverage {
public DarkRoast() {
description = "黑莓咖啡";
}
@Override
public Double cost() {
return 21.8;
}
}
3、下面我們實作調料類的抽象類,也就是裝飾者類
/**
* 調料抽象類
*/
public abstract class Condiment extends Beverage {
Beverage beverage;
Condiment(Beverage decoratedBeverage){
this.beverage = decoratedBeverage;
}
public abstract String getDescription();
}
4、 然后我們再實作相應的 Mocha、Whip、Soy 的調料代碼
/**
* 摩卡
*/
public class Mocha extends Condiment {
public Mocha(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + "【摩卡】";
}
@Override
public Double cost() {
return new BigDecimal(beverage.cost().toString()).add(new BigDecimal(2.2)).doubleValue();
}
}
/**
* 豆漿
*/
public class Soy extends Condiment {
public Soy(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription(){
return beverage.getDescription() + "【豆漿】";
}
@Override
public Double cost() {
return new BigDecimal(beverage.cost().toString()).add(new BigDecimal(3.6)).doubleValue();
}
}
/**
* 奶泡
*/
public class Whip extends Condiment {
public Whip(Beverage beverage){
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + "【奶泡】";
}
@Override
public Double cost() {
return new BigDecimal(beverage.cost().toString()).add(new BigDecimal(2.7)).doubleValue();
}
}
好了,參考裝飾者模式,訂單模塊的基本實作已經基本完成,下面是測驗代碼
public class Client {
public static void main(String[] args) {
//一杯DarkRoast 不需要調料
Beverage darkRoast = new DarkRoast();
System.out.println(darkRoast.getDescription() + "," + darkRoast.cost());
//再點一個濃縮咖啡 加 雙倍摩卡 一份奶泡
Beverage beverage = new Expresso();
beverage = new Mocha(beverage);
beverage = new Mocha(beverage);
beverage = new Whip(beverage);
System.out.println(beverage.getDescription() + "," + beverage.cost());
}
}

IO體系中的裝飾器

由圖可見,InputStream就是裝飾者模式中的超類(Component),
ByteArrayInputStream,FileInputStream相當于 被裝飾者(ConcreteComponent),這些類都提供了最基本的位元組讀取功能,
而另外一個和這兩個類是同一級的類FilterInputStream 即為 抽象裝飾者(AbstarctDecorator)
BufferedInputStream,DataInputStream,PushbackInputStream(都繼承了FilterInputStream類),它們為 裝飾者(Decorator),在原有基礎功能上都實作了功能的擴展和增強,
例:用BufferedInputStream 裝飾 FileInputStream,和上面Mocha(摩卡) 裝飾 DarkRoast(黑莓)如出一轍
File file = new File ("hello.txt");
FileInputStream in=new FileInputStream(file);
BufferedInputStream inBuffered=new BufferedInputStream (in);
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/3104.html
標籤:設計模式
上一篇:單例模式
下一篇:設計模式6大原則詳解
