設計模式學習筆記--裝飾者模式(Decorator Pattern)
概念
動態地將行為附加到物件上。提供了比繼承更具有彈性的替代方案
所謂”動態”,是指在執行時根據具體的需求新增行為,相對的,”靜態”則是在編譯時就確定了具體的行為,兩者的區別很明顯,動態新增行為具有很好的可擴充套件性,不需要修改已有的程式碼,這對於維護更新是很有利的。
設計原則
類應該對擴充套件開放,對修改關閉
對原有程式碼修改的代價是很大的,很可能引入未知的 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());
}
}
執行結果: