1. 程式人生 > >設計模式學習筆記--裝飾者模式(Decorator Pattern)

設計模式學習筆記--裝飾者模式(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());
    }
}

執行結果:

這裡寫圖片描述