裝飾模式
個人博客,想要搭建個人博客的可以進來看看: http://www.ioqian.top/
裝飾模式,動態的將責任附加到對象上。若要擴展功能,裝飾者提供了比繼承更有彈性的替代方案,在Java JDK的io實現中使用了大量的裝飾者模式
設計模式系列博客博主源碼: https://github.com/liloqian/DesiginModeDemo
背景
我們要幫星巴克提供一個自動打印咖啡信息和價格的軟件,比如基礎的濃縮咖啡,混合咖啡,每個基礎咖啡加了什麼調料(幾分糖,幾分牛奶等等)。如果我們對每種咖啡具體實現,這簡直是類爆炸,每個人有自己的咖啡配料方式,要寫幾萬個類… 我們這裏要是有裝飾模式
我們先來看一下裝飾者模式的UML
通過我們的背景來生動的描述
結合UML和我們的模擬場景說明一下
- Component 公共父類,這裏就是我們的咖啡父類,下面的調料和基本咖啡類型都要繼承Component
- ConcreteComponent 被裝飾者,相當於我們的基本咖啡類型我們有兩種
- Decorator,裝飾者 ,相當於調料接口,這個接口的任意實現都可以包裝咖啡父類的實現者,我這裏也用了接口
- ConcreateDecoratorA ,這裏相當於上圖右下角的牛奶加糖的濃縮咖啡,一個裝飾例子
裝飾者模式的特點
- 裝飾者和被裝飾者有共同的超類型
- 裝飾對象包含一個真實對象的引用
- 可以用多個裝飾對象包裝一個被裝飾對象
- 對象可以在任何時候被裝飾
下面來看代碼實現,就是上面我們的模擬情景
公共父類的實現
//裝飾者和被裝飾者的公共父類
public abstract class Beverage {
//父類狀態描述
String description = "Base Beverage";
//具體的價格讓基本咖啡類型加上裝飾者的價格確定
public abstract double cost();
public String getDescription() {
return description;
}
}
兩種基本咖啡類型,濃縮咖啡和混合咖啡
濃縮咖啡
//濃縮咖啡類型 ,繼承了父類
public class Espresso extends Beverage {
public Espresso() {
description = "Espresso coffee";
}
//濃縮咖啡的價格
@Override
public double cost() {
return 1.9;
}
}
混合咖啡
//混合咖啡
public class Blend extends Beverage {
public Blend() {
description = "Blend coffee";
}
//混合咖啡價格
@Override
public double cost() {
return 2.9;
}
}
調料接口
//調料接口,和基本咖啡類型有共同的父類
public abstract class Spices extends Beverage {
public abstract String getDescription();
}
調料糖
public class Sugar extends Spices {
Beverage beverage;
//我們用父類,不要基本的咖啡類型
public Sugar(Beverage beverage) {
this.beverage = beverage;
}
//修飾咖啡名稱狀態, 修飾屬性+基本屬性
@Override
public String getDescription() {
return "Sugar " + beverage.getDescription();
}
//修飾咖啡價格 糖的價格加上自身本來價格
@Override
public double cost() {
return .5 + beverage.cost();
}
}
調料牛奶,和上面類似
public class Milk extends Spices {
Beverage beverage;
public Milk(Beverage beverage) {
this.beverage = beverage;
}
@Override
public double cost() {
return 0.3 + beverage.cost();
}
@Override
public String getDescription() {
return "Milk "+beverage.getDescription();
}
}
main測試
public class Main {
public static void main(String[] args) {
//普通的混合咖啡
Beverage blend = new Blend();
printInfo(blend);
//加了一份牛奶的混合咖啡
Beverage blendMilk = new Milk(blend);
printInfo(blendMilk);
//加了2份糖的一份牛奶的混合咖啡
Beverage blendMilkSugarTwo = new Sugar(new Sugar(blendMilk));
printInfo(blendMilkSugarTwo);
//加了一份糖一份牛奶的濃縮咖啡
Beverage espresson = new Sugar(new Milk(new Espresso()));
printInfo(espresson);
}
//提取打印咖啡的打印方法
private static void printInfo(Beverage beverage){
System.out.println(beverage.getDescription() +" 價格:"+beverage.cost());
}
}
結果
Blend coffee 價格:2.9
Milk Blend coffee 價格:3.1999999999999997
Sugar Sugar Milk Blend coffee 價格:4.199999999999999
Sugar Milk Espresso coffee 價格:2.6999999999999997
Process finished with exit code 0
裝飾者模式用到的設計原則
開閉原則對擴展開發,對修改關閉原則 , 沒有太多的感悟,在後面的源碼中尋找想法,歡迎大神用通俗的話語概況