【設(shè)計(jì)模式筆記】(十九)- 裝飾者模式

簡(jiǎn)述

裝飾者模式(Decorator Pattern)也稱為包裝模式(Wrapper Pattern),以透明動(dòng)態(tài)的方式來(lái)動(dòng)態(tài)擴(kuò)展對(duì)象的功能,也是繼承關(guān)系的一種代替方案。

裝飾模式.png
  • Component:抽象組件(可以是抽象類或者接口),被裝飾的原始對(duì)象
  • ConcreteComponent:具體實(shí)現(xiàn)類,被裝飾的具體對(duì)象
  • Decorator:抽象裝飾者,職責(zé)就是為了裝飾我們的組件對(duì)象,內(nèi)部一定要有一個(gè)指向組件對(duì)象的引用
  • ConcreteDecoratorA:裝飾者具體實(shí)現(xiàn)類,只對(duì)抽象裝飾者做出具體實(shí)現(xiàn)
  • ConcreteDecoratorB:同上

舉個(gè)栗子

人定義為抽象類,有一個(gè)抽象方法eat()

public abstract class Person {
    public abstract void eat();
}

接著創(chuàng)建一個(gè)NormalPerson類繼承Person,對(duì)eat()方法有了具體實(shí)現(xiàn);NormalPerson類就是我們需要裝飾的對(duì)象。

public class NormalPerson extends Person {
    @Override
    public void eat() {
        System.out.println("吃飯");
    }
}

這里定義一個(gè)PersonFood類來(lái)表示裝飾者的抽象類,保持了一個(gè)對(duì)Person的引用,可以方便調(diào)用具體被裝飾的對(duì)象方法,這樣就可以方便的對(duì)其進(jìn)行擴(kuò)展功能,并且不改變?cè)惖膶哟谓Y(jié)構(gòu)。

public class PersonFood extends Person {
    private Person person;

    public PersonFood(Person person){
        this.person = person;
    }

    @Override
    public void eat() {
        person.eat();
    }
}

接著就是具體的裝飾類了,這兩個(gè)類沒(méi)有本質(zhì)上的區(qū)別,都是為了擴(kuò)展NormalPerson類,不修改原有類的方法和結(jié)構(gòu)

public class ExpensiveFood extends PersonFood {
    public ExpensiveFood(Person person) {
        super(person);
    }

    @Override
    public void eat() {
        super.eat();
        eatSteak();
        drinkRedWine();
    }

    public void eatSteak(){
        System.out.println("吃牛排");
    }

    public void drinkRedWine(){
        System.out.println("喝拉菲");
    }

}

public class CheapFood extends PersonFood {
    public CheapFood(Person person) {
        super(person);
    }

    @Override
    public void eat() {
        super.eat();
        eatNoodles();
    }

    public void eatNoodles(){
        System.out.println("吃面條");
    }
}

客戶端代碼

public class Client {
    public static void main(String[] args){
        Person person = new NormalPerson();

        PersonFood cheapFood = new CheapFood(person);
        cheapFood.eat();

        PersonFood expensiveFood = new ExpensiveFood(person);
        expensiveFood.eat();
    }
}

android中的裝飾者模式

android中,Context就是典型的裝飾者模式,Context是抽象類,真實(shí)的功能實(shí)現(xiàn)實(shí)在ComtextImpl中完成,ComtextImpl就是Context的實(shí)現(xiàn)類;然后看源碼會(huì)發(fā)現(xiàn)Activity是繼承于ContextThemeWrapper而不是直接繼承于Context。其中ContextThemeWrapper 繼承于ContextWrapper,而ContextWrapper繼承于Context。這里就可以看出來(lái)一點(diǎn)裝飾者模式了,其中裝飾者所調(diào)用的方法就是startActivity方法,在ContextWrapper中會(huì)發(fā)現(xiàn)startActivity方法調(diào)用了ComtextImpl中對(duì)應(yīng)的方法,實(shí)質(zhì)上ContextWrapper中所有方法都僅僅是調(diào)用了ComtextImpl中的方法,這就和裝飾者模式基本就對(duì)應(yīng)上了。

優(yōu)點(diǎn)

  • 裝飾者模式與繼承關(guān)系的目的都是要擴(kuò)展對(duì)象的功能,但是裝飾者模式可以提供比繼承更多的靈活性。
  • 通過(guò)使用不同的具體裝飾類以及這些裝飾類的排列組合,設(shè)計(jì)師可以創(chuàng)造出很多不同行為的組合。

缺點(diǎn)

  • 這種比繼承更加靈活機(jī)動(dòng)的特性,也同時(shí)意味著更加多的復(fù)雜性。
  • 裝飾模式會(huì)導(dǎo)致設(shè)計(jì)中出現(xiàn)許多小類,如果過(guò)度使用,會(huì)使程序變得很復(fù)雜。
  • 裝飾模式是針對(duì)抽象組件(Component)類型編程。但是,如果你要針對(duì)具體組件編程時(shí),就應(yīng)該重新思考你的應(yīng)用架構(gòu),以及裝飾者是否合適。當(dāng)然也可以改變Component接口,增加新的公開的行為,實(shí)現(xiàn)“半透明”的裝飾者模式。在實(shí)際項(xiàng)目中要做出最佳選擇。

與代理模式的區(qū)別

其實(shí)裝飾者模式和代理模式很像,但是兩者的目的不盡相同。裝飾者模式是以對(duì)客戶端透明的方式擴(kuò)展對(duì)象的功能,是繼承關(guān)系的一個(gè)替代方案;而代理模式則是一個(gè)給對(duì)象提供一個(gè)代理對(duì)象,并由代理對(duì)象來(lái)控制對(duì)原有對(duì)象的引用。

裝飾者模式為本裝飾的對(duì)象進(jìn)行功能擴(kuò)展;代理模式對(duì)代理對(duì)象進(jìn)行控制,但不做功能擴(kuò)展

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容