1. 簡介
裝飾者模式是一種結構型模式,它可以動態的將責任附加到物件上,在擴充套件功能方面,它比繼承更有彈性。裝飾者模式遵循了開閉原則,對擴充套件開放,對修改關閉。
雖然在裝飾者模式中也使用了繼承,但是繼承只是為了與被裝飾者擁有共同的父類,達到型別匹配的目的,而不是為了獲得父類的行為。因為裝飾者與被裝飾者擁有共同的父類,所以在任何需要原始物件的場合,都可以用裝飾過的物件替代它。但是在使用裝飾者模式的同時可能會引入大量小類,而且使用裝飾者模式除了例項化元件外,還要把元件包裝進裝飾者,會使程式碼顯得不易理解。
2. UML類圖
ConcreteComponent是具體元件,也就是被裝飾者。Decorator是抽象裝飾者,與ConcreteComponent擁有共同的超類Component————它是一個抽象元件,在具體裝飾者ConcreteDecoratorA和ConcreteDecoratorB中有一個例項變數,可以記錄被裝飾的事物。
3. 例項
去食堂吃飯,假如你想吃麵條,食堂有牛肉麵和熱乾麵,還可以加青菜、煎蛋、香腸等配料,以後還可能增加更多的配料,在計算價格時需要根據不同的配料來計算,這裡就可以用到裝飾者模式。
抽象元件:
public abstract class Noodles {
protected String desc;
public String getDesc() {
return desc;
}
public abstract double cost();
}
具體元件:
public class BeefNoodles extends Noodles {
public BeefNoodles() {
desc = "Beef Noodles.";
}
public double cost() {
return 10.0;
}
}
public class HotDryNoodles extends Noodles {
public HotDryNoodles() {
desc = "Hot Dry Noodles.";
}
public double cost() {
return 8.0;
}
}
抽象裝飾者:
//繼承自Noodles,使裝飾者與元件擁有共同的超類
public abstract class Condiment extends Noodles {
public abstract String getDesc();
}
具體裝飾者:
public class Vegetable extends Condiment {
private Noodles noodles;
public Vegetable(Noodles noodles) {
this.noodles = noodles;
}
public String getDesc() {
return noodles.getDesc() + ", vegetable";
}
public double cost() {
return noodles.cost() + 2.0;
}
}
public class Egg extends Condiment {
private Noodles noodles;
public Egg(Noodles noodles) {
this.noodles = noodles;
}
public String getDesc() {
return noodles.getDesc() + ", egg";
}
public double cost() {
return noodles.cost() + 3.0;
}
}
public class Sausage extends Condiment {
private Noodles noodles;
public Sausage(Noodles noodles) {
this.noodles = noodles;
}
public String getDesc() {
return noodles.getDesc() + ", Sausage";
}
public double cost() {
return noodles.cost() + 4.0;
}
}
測試:
public class Test {
public static void main(String[] args) {
Noodles noodles = new BeefNoodles();
System.out.println(noodles.getDesc() + ", " + noodles.cost());
noodles = new Vegetable(noodles);
noodles = new Egg(noodles);
noodles = new Sausage(noodles);
System.out.println(noodles.getDesc() + ", " + noodles.cost());
}
}