裝飾者模式
裝飾模式指的是在不必改變原類文件和使用繼承的情況下,動態地擴展一個對象的功能。它是通過創建一個包裝對象,也就是裝飾來包裹真實的對象。
首先來分析一下爲什麼使用裝飾者模式。例如,讓一個對象添加一個新的功能,我們第一想到的就是創建一個類來繼承這個類,然後添加新的功能方法。這種方式在大部分簡單的場景中是可取的,可是也有一些複雜的情況。例如,各種功能之間要相互組合使用,拿手抓餅來說吧,一個手抓餅裏面可以加各種食材,比如加個烤腸,加個雞蛋等等,我以前上班的時候路過地鐵站都會買一個手抓餅當早餐,既美味,又方便。平時的時候我加一個雞蛋,一份青菜,當我發工資的時候我就闊綽一把,加一個雞蛋,一份青菜,再加一個烤腸。可見手抓餅裏的東西是可以隨意組合的,假如說我們用繼承的方式,我想加一個雞蛋和一份青菜,那麼我就要創建一個子類來繼承手抓餅,在子類中組合雞蛋和青菜。如果我想加一個雞蛋一份青菜和一根烤腸,那麼我就要再創建一個子類來繼承手抓餅,在子類中組合雞蛋青菜和烤腸。當然,可能月底了,沒錢了,我只加一個雞蛋,那麼就又多了一種組合方式,可見,這種組合方式是特別多的,如果使用繼承,那麼子類將會多到爆炸。過些時候老闆又推出了新的食品,可以加裏脊肉了,那麼多一種食品,它們的組合方式將會成幾何的方式增長,顯然這種場景下,使用繼承的方式是不可取的,那麼這個時候就可以使用裝飾者模式了。
裝飾模式的使用場景:
裝飾模式的優點:
示例代碼:
抽象手抓餅接口:
/**
* 手抓餅抽象
*/
public interface HandPancake {
String description(); //描述
float price(); //價格
}
創建手抓餅實例:
public class Pancake implements HandPancake{
private String description="煎餅";
private float price =4;
@Override
public String description() {
return description;
}
@Override
public float price() {
return price;
}
}
抽象手抓餅組合的食材基類:
public abstract class Decorator implements HandPancake{
protected HandPancake handPancake;
public Decorator(HandPancake handPancake){
this.handPancake=handPancake;
}
}
創建雞蛋食材實例:
public class Egg extends Decorator {
private String description="雞蛋";
private float price =1;
public Egg(HandPancake handPancake){
super(handPancake);
}
@Override
public String description() {
return handPancake.description()+"+"+description;
}
@Override
public float price() {
return handPancake.price()+price;
}
}
創建青菜食材實例:
public class Greens extends Decorator {
private String description="青菜";
private float price =0.5f;
public Greens(HandPancake handPancake) {
super(handPancake);
}
@Override
public String description() {
return handPancake.description() + "+" + description;
}
@Override
public float price() {
return handPancake.price() + price;
}
}
創建熱狗食材實例:
public class HotDog extends Decorator {
private String description="熱狗";
private float price =2;
public HotDog(HandPancake handPancake) {
super(handPancake);
}
@Override
public String description() {
return handPancake.description() + "+" + description;
}
@Override
public float price() {
return handPancake.price() + price;
}
}
現在可以自由搭配買手抓餅了
/**
* 手抓餅4元
* 加雞蛋1元
* 加熱狗2元
* 加青菜0.5元
* 上海手抓餅好貴啊,現在我都不吃了
*/
public class Test {
public static void main(String[] args) {
HandPancake pancake = new Pancake(); //一份手抓餅
pancake = new Egg(pancake); //加個雞蛋
pancake = new Greens(pancake); //加點青菜
System.out.println("你買的是:" + pancake.description() + "\t總計:" + pancake.price() + "元");
pancake = new HotDog(pancake); //再加根烤腸吧
System.out.println("你買的是:" + pancake.description() + "\t總計:" + pancake.price() + "元");
}
}
運行結果:
可以看到,使用裝飾者模式,各個食材之間可以隨意組合,並沒有出現類的爆炸性增長。在java中,裝飾者模式使用最經典的就是IO流了,大家可以去操作一下IO流,體會一下裝飾者模式的特點。