裝飾者模式允許為一個組件(component)添加不同的裝飾者(decorator)液样,從而在不改變代碼的情況下更改組件的功能探赫。這是一種繼承的替換方案痢艺,我們可以使用裝飾者模式對某個組件進(jìn)行不斷的擴(kuò)充店量,從而拓展他的功能翘紊。
遵循的設(shè)計(jì)原則
- 面相接口編程:
裝飾者模式中的抽象組件和抽象裝飾者余佃,都是將我們需要加強(qiáng)的方法拿出來暮刃,放在接口之中,這樣我們在使用的時候會更加靈活且耦合度更低 - 封裝變化:
裝飾者模式將我們需要加強(qiáng)的方法放入接口之中爆土,這樣我們在使用的時候不會影響到被封裝的部分
3.開閉原則:
對擴(kuò)展開放椭懊,對修改關(guān)閉。在裝飾者模式中步势,因?yàn)樗械姆庋b者都繼承自component氧猬,每當(dāng)有新的裝飾者出現(xiàn)背犯,他會將之前的decorator+component當(dāng)成為一個component 來看待,這時候除了接口中暴露出來的方法外盅抚,其他的部分已經(jīng)被封裝了起來漠魏。
如何實(shí)現(xiàn)
裝飾者模式一共由四部分組成
1.抽象組件component,這是一個超類(抽象類或者接口)妄均,我們需要不斷對這個接口中的方法進(jìn)行強(qiáng)化和拓展柱锹。
2.具體組件concreteComponent, 這是超類的具體實(shí)現(xiàn),也被成為被裝飾者(decorated object), 即我們要裝飾的類丛晦。
3.抽象裝飾者decorator, 這是所有裝飾者的抽象(超類)奕纫,里面聲明了我們需要加強(qiáng)和拓展的方法。他是compoent的子類型(繼承/實(shí)現(xiàn)了compoent抽象類/接口)
4.具體裝飾者concreteDecorator, 這是裝飾者的實(shí)例烫沙,裝飾者們持有具體組件的引用匹层,并且對于需要加強(qiáng)的的內(nèi)容有自己的實(shí)現(xiàn)。
裝飾者模式锌蓄,是的升筏,還是網(wǎng)圖。瘸爽。
一句提醒
裝飾者模式加強(qiáng)的并不是具體組件 ConcreteComponent, 而是compoent接口中暴露出的方法您访。
實(shí)戰(zhàn)演示
/**
* Created by LeafEater on 2017/2/18.
* 需求:要求為一家煎餅店做一個點(diǎn)餐系統(tǒng)
* 煎餅類型: 雜糧煎餅 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;
}
}
再總結(jié)一下
裝飾者模式在說這樣一個場景:隨著業(yè)務(wù)的推進(jìn),舊系統(tǒng)中的功能已經(jīng)不夠用了剪决,我們需要在利用舊系統(tǒng)的基礎(chǔ)上增加新的功能灵汪。
之后再看看我們設(shè)計(jì)的思路是什么:
- 我們需要使用舊系統(tǒng),那么一定會獲得舊系統(tǒng)的引用柑潦,所以說在新系統(tǒng)Decorator中享言,我們引入了舊系統(tǒng)ConcreteComponent的引用
- 我們還需要對舊系統(tǒng)做一定程度的改造或者增強(qiáng),首先分析出舊系統(tǒng)中向外提供的服務(wù)渗鬼,這個服務(wù)就是operation();將這種服務(wù)抽象成接口之后览露,再在新系統(tǒng)中實(shí)現(xiàn)它,就可以對這個服務(wù)進(jìn)行一些自定義譬胎。這時候再看看第一步差牛,我們也擁有舊系統(tǒng)中operation的實(shí)現(xiàn)方式,所以就可以在Operation的基礎(chǔ)上進(jìn)行一定的增強(qiáng)堰乔。