裝飾者模式允許為一個組件(component)添加不同的裝飾者(decorator),從而在不改變代碼的情況下更改組件的功能。這是一種繼承的替換方案,我們可以使用裝飾者模式對某個組件進行不斷的擴充,從而拓展他的功能。
遵循的設計原則
- 面相接口編程:
裝飾者模式中的抽象組件和抽象裝飾者,都是將我們需要加強的方法拿出來,放在接口之中,這樣我們在使用的時候會更加靈活且耦合度更低 - 封裝變化:
裝飾者模式將我們需要加強的方法放入接口之中,這樣我們在使用的時候不會影響到被封裝的部分
3.開閉原則:
對擴展開放,對修改關閉。在裝飾者模式中,因為所有的封裝者都繼承自component,每當有新的裝飾者出現,他會將之前的decorator+component當成為一個component 來看待,這時候除了接口中暴露出來的方法外,其他的部分已經被封裝了起來。
如何實現
裝飾者模式一共由四部分組成
1.抽象組件component,這是一個超類(抽象類或者接口),我們需要不斷對這個接口中的方法進行強化和拓展。
2.具體組件concreteComponent, 這是超類的具體實現,也被成為被裝飾者(decorated object), 即我們要裝飾的類。
3.抽象裝飾者decorator, 這是所有裝飾者的抽象(超類),里面聲明了我們需要加強和拓展的方法。他是compoent的子類型(繼承/實現了compoent抽象類/接口)
4.具體裝飾者concreteDecorator, 這是裝飾者的實例,裝飾者們持有具體組件的引用,并且對于需要加強的的內容有自己的實現。
裝飾者模式,是的,還是網圖。。
一句提醒
裝飾者模式加強的并不是具體組件 ConcreteComponent, 而是compoent接口中暴露出的方法。
實戰演示
/**
* Created by LeafEater on 2017/2/18.
* 需求:要求為一家煎餅店做一個點餐系統
* 煎餅類型: 雜糧煎餅 6元 白面煎餅 5元
* 加料: 辣條 1元 雞蛋 1元 火腿 2元
*/
public class OrderSystem {
public static void main(String[] args) {
Pancakes pancakes = new MixedPancakes();
pancakes = new Ham(pancakes);
pancakes = new Egg(pancakes);
Pancakes pancakes1 = new Latiao(new Egg(new FlourPancakes()));
System.out.println("訂單:" + pancakes.getDescription());
System.out.println("價格:" + pancakes.cost());
System.out.println("訂單:" + pancakes1.getDescription());
System.out.println("價格:" + pancakes1.cost());
}
}
interface Pancakes {
public abstract String getDescription();
public abstract int cost();
}
abstract class Seasoning implements Pancakes {
@Override
public abstract String getDescription();
}
class Ham extends Seasoning {
Pancakes pancakes;
public Ham(Pancakes pancakes) {
this.pancakes = pancakes;
}
@Override
public int cost() {
return pancakes.cost() + 2;
}
@Override
public String getDescription() {
return pancakes.getDescription() + "+火腿";
}
public void hamState() {
System.out.println("火腿切碎");
}
}
class Egg extends Seasoning {
Pancakes pancakes;
public Egg(Pancakes pancakes) {
this.pancakes = pancakes;
}
@Override
public int cost() {
return pancakes.cost() + 1;
}
@Override
public String getDescription() {
return pancakes.getDescription() + "+雞蛋";
}
public void eggState() {
System.out.println("雞蛋打碎");
}
}
class Latiao extends Seasoning {
Pancakes pancakes;
public Latiao(Pancakes pancakes) {
this.pancakes = pancakes;
}
@Override
public int cost() {
return pancakes.cost() + 1;
}
@Override
public String getDescription() {
return pancakes.getDescription() + "+辣條";
}
}
class MixedPancakes implements Pancakes {
@Override
public String getDescription() {
return "五谷雜糧煎餅";
}
@Override
public int cost() {
return 6;
}
}
class FlourPancakes implements Pancakes {
@Override
public String getDescription() {
return "白面煎餅";
}
@Override
public int cost() {
return 5;
}
}
再總結一下
裝飾者模式在說這樣一個場景:隨著業務的推進,舊系統中的功能已經不夠用了,我們需要在利用舊系統的基礎上增加新的功能。
之后再看看我們設計的思路是什么:
- 我們需要使用舊系統,那么一定會獲得舊系統的引用,所以說在新系統Decorator中,我們引入了舊系統ConcreteComponent的引用
- 我們還需要對舊系統做一定程度的改造或者增強,首先分析出舊系統中向外提供的服務,這個服務就是operation();將這種服務抽象成接口之后,再在新系統中實現它,就可以對這個服務進行一些自定義。這時候再看看第一步,我們也擁有舊系統中operation的實現方式,所以就可以在Operation的基礎上進行一定的增強。