概念
動態地將行爲附加到對象上。提供了比繼承更具有彈性的替代方案
所謂”動態”,是指在運行時根據具體的需求添加行爲,相對的,”靜態”則是在編譯時就確定了具體的行爲,兩者的區別很明顯,動態添加行爲具有很好的可擴展性,不需要修改已有的代碼,這對於維護更新是很有利的。
設計原則
類應該對擴展開放,對修改關閉
對原有代碼修改的代價是很大的,很可能引入未知的 bug 和意外的副作用,所以要對修改關閉,而使用擴展來應對改變的需求,在不修改原有代碼的情況下就能添加新行爲。多用組合,少用繼承
如同策略模式,使用繼承設計子類的行爲,是在編譯時靜態決定的,而且所有的子類都會繼承到相同的行爲,而如果使用組合來擴展對象的行爲,就可以在運行時動態的添加行爲。
理解
在裝飾者模式中,存在兩個角色:組件(Component) 和 裝飾器(Decorator),並且兩者要實現相同的接口或抽象類(實現接口或繼承抽象類都行),這樣就可以使用裝飾器來裝飾組件了。現實生活中有很多這樣的例子,比如購買手機時,一個裸機就算是一個組件,如果想要裝飾下手機,加個手機套,貼個膜,送支手寫筆等,這些就是裝飾器。通過裝飾,在原有對象的基礎上得到了一個新的具有更多屬性和行爲的對象,比如加了手機套的手機比裸機耐摔,這便是裝飾後得到的新屬性;有了手寫筆的手機可以有新的輸入方式,這便是裝飾後得到的新行爲。
實例
現實生活中有很多事物可以描述裝飾者模式,就拿上面提到的手機配件的例子來寫一個模擬代碼
在這個例子中,有一個抽象類 Phones,作爲組件和裝飾器的共同基類;有兩個組件,AndroidPhone 和 iOSPhone,裝飾器數量不確定,因此有個裝飾器基類 PhoneAccessory,然後派生出一些可選的裝飾器,比如 手機殼:PhoneCover,手機膜:PhoneMembrane,手寫筆:PhonePen。他們之間的關係可以用如下類圖描述
通過類圖可以很清楚的看到裝飾者模式的思路,下面是具體代碼:
抽象基類
public abstract class Phones {
String description="nothing";
public String getDescription(){
return description;
}
}
Android 手機
public class AndroidPhone extends Phones {
public AndroidPhone(){
description="Android 手機";
}
}
iOS 手機
public class iOSPhone extends Phones {
public iOSPhone(){
description="iOS 手機";
}
}
裝飾器基類
public abstract class PhoneAccessory extends Phones {
public abstract String getDescription();
}
手機殼裝飾器
public class PhoneCover extends PhoneAccessory{
private Phones phone;
public PhoneCover(Phones p){
this.phone=p;
}
@Override
public String getDescription() {
return this.phone.getDescription()+" 加了個保護套";
}
}
手機膜裝飾器
public class PhoneMembrane extends PhoneAccessory {
private Phones phones;
public PhoneMembrane(Phones p){
this.phones=p;
}
@Override
public String getDescription() {
return this.phones.getDescription()+" 貼了個膜";
}
}
手寫筆裝飾器
public class PhonePen extends PhoneAccessory{
private Phones phone;
public PhonePen(Phones p){
this.phone=p;
}
@Override
public String getDescription() {
return this.phone.getDescription()+" 送了支手寫筆";
}
}
測試
public class MainTest {
public static void main(String[] args) {
Phones phone = new AndroidPhone();
System.out.println(phone.getDescription());
PhoneCover coverPhone = new PhoneCover(phone);
System.out.println(coverPhone.getDescription());
PhoneMembrane membranePhone = new PhoneMembrane(coverPhone);
System.out.println(membranePhone.getDescription());
PhonePen penPhone = new PhonePen(membranePhone);
System.out.println(penPhone.getDescription());
}
}
運行結果: