想象一下,你走進一家咖啡館,點了一杯美式咖啡。但是,你可能還想根據自己的口味添加一些東西,比如奶泡、巧克力粉、焦糖醬或是肉桂粉。每次你添加一種配料,你的咖啡就會變得更豐富,同時價格也會相應增加。
在軟件設計中,裝飾者模式就是讓你能夠在不改變原始對象的情況下,動態地給它添加新功能或增強現有功能。這就好比你在咖啡上加配料,不是通過制作一種全新的咖啡,而是通過在現有的基礎上增加東西。
比如,假設你正在開發一個文本編輯器,你希望用戶可以選擇開啟一些額外的功能,比如語法高亮、行號顯示、自動完成等。你不想為每一種可能的組合都創建一個單獨的文本編輯器類,因為那樣會有無數種組合,維護起來會非常困難。
這時,裝飾者模式就派上用場了。你可以創建一個基本的文本編輯器類,然后為每一個額外功能創建一個裝飾者類。當用戶選擇開啟某項功能時,你就在基本的文本編輯器上“裝飾”上相應的裝飾者。這樣,用戶就可以根據自己的需求,動態地定制他們自己的文本編輯器,而不需要重新編寫整個程序。
簡而言之,裝飾者模式就像是給你的軟件產品添加“配料”,讓它變得更有個性,更符合用戶的需求,而無需更改其核心結構。
?以一家奶茶店為例,使用裝飾者模式來動態地給奶茶添加各種配料。我們將創建一個基礎的奶茶類,然后使用裝飾者類來添加不同的配料,如珍珠、布丁、紅豆、仙草、芝士等。
首先,我們定義奶茶的基本接口:
public abstract class Drink {// 基本屬性protected String description = "Unknown Drink";// 獲取描述public String getDescription() {return description;}// 設置描述public void setDescription(String description) {this.description = description;}// 抽象方法,計算價格public abstract double cost();
}
接下來,我們創建基礎的奶茶類:
public class MilkTea extends Drink {public MilkTea() {description = "Milk Tea";}public double cost() {return 3.5; // 假設一杯基礎奶茶的價格是3.5元}
}
然后,我們定義裝飾者基類:
public abstract class AddOns extends Drink {protected Drink drink;public AddOns(Drink drink) {this.drink = drink;}public String getDescription() {return drink.getDescription();}public double cost() {return drink.cost();}
}
接著,我們創建具體的配料裝飾者:
public class Boba extends AddOns {public Boba(Drink drink) {super(drink);}@Overridepublic String getDescription() {// 返回被裝飾對象的描述return super.getDescription()+", with Boba";}@Overridepublic double cost() {return drink.cost() + 1.0; // 添加珍珠的成本}
}
public class Pudding extends AddOns {public Pudding(Drink drink) {super(drink);}@Overridepublic String getDescription() {// 返回被裝飾對象的描述return super.getDescription()+", with Pudding";}@Overridepublic double cost() {return drink.cost() + 0.8; // 添加布丁的成本}
}
public class RedBeans extends AddOns {public RedBeans(Drink drink) {super(drink);}@Overridepublic String getDescription() {// 返回被裝飾對象的描述return super.getDescription()+", with Red Beans";}@Overridepublic double cost() {return drink.cost() + 0.7; // 添加紅豆的成本}
}
最后,在主函數中使用這些裝飾者:
public class Main {public static void main(String[] args) {Drink milkTea = new MilkTea();System.out.println(milkTea.getDescription() + ": " + milkTea.cost());Drink milkTeaWithBoba = new Boba(milkTea);System.out.println(milkTeaWithBoba.getDescription() + ": " + milkTeaWithBoba.cost());Drink milkTeaWithBobaAndPudding = new Pudding(milkTeaWithBoba);System.out.println(milkTeaWithBobaAndPudding.getDescription() + ": " + milkTeaWithBobaAndPudding.cost());Drink milkTeaWithBobaAndRedBeans = new RedBeans(milkTeaWithBoba);System.out.println(milkTeaWithBobaAndRedBeans.getDescription() + ": " + milkTeaWithBobaAndRedBeans.cost());}
}
執行結果
Milk Tea: 3.5
Milk Tea, with Boba: 4.5
Milk Tea, with Boba, with Pudding: 5.3
Milk Tea, with Boba, with Red Beans: 5.2
在上述代碼中,Drink
是奶茶及其配料的抽象基類,MilkTea
是基本的奶茶實現,AddOns
是所有配料的基類,而Boba
, Pudding
, RedBeans
分別是具體的配料裝飾者。通過組合不同的裝飾者,我們可以輕松地構建出各種不同配料組合的奶茶,而且這些組合是在運行時動態決定的。
理解這種思想然后之后就是如何熟練運用,在有需要的時候。