設(shè)計(jì)模式之修飾器模式詳解(附源代碼)

裝飾器模式

裝飾器模式(Decorator Pattern)允許向一個(gè)現(xiàn)有的對(duì)象添加新的功能,同時(shí)又不改變其結(jié)構(gòu)。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它是作為現(xiàn)有的類的一個(gè)包裝。
這種模式創(chuàng)建了一個(gè)裝飾類,用來(lái)包裝原有的類,并在保持類方法簽名完整性的前提下,提供了額外的功能。


介紹

意圖: 動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)。就增加功能來(lái)說(shuō),裝飾器模式相比生成子類更為靈活。
主要解決: 一般的,我們?yōu)榱藬U(kuò)展一個(gè)類經(jīng)常使用繼承方式實(shí)現(xiàn),由于繼承為類引入靜態(tài)特征,并且隨著擴(kuò)展功能的增多,子類會(huì)很膨脹。
何時(shí)使用:在不想增加很多子類的情況下擴(kuò)展類。
如何解決: 將具體功能職責(zé)劃分,同時(shí)繼承裝飾者模式。
關(guān)鍵代碼:

  1. Component 類充當(dāng)抽象角色,不應(yīng)該具體實(shí)現(xiàn)。
  2. 修飾類引用和繼承 Component 類,具體擴(kuò)展類重寫父類方法。

優(yōu)點(diǎn): 裝飾類和被裝飾類可以獨(dú)立發(fā)展,不會(huì)相互耦合,裝飾模式是繼承的一個(gè)替代模式,裝飾模式可以動(dòng)態(tài)擴(kuò)展一個(gè)實(shí)現(xiàn)類的功能。
缺點(diǎn): 多層裝飾比較復(fù)雜。(無(wú)法直觀的了解一個(gè)被裝飾類的全貌)
使用場(chǎng)景:

  1. 擴(kuò)展一個(gè)類的功能。
  2. 動(dòng)態(tài)增加功能,動(dòng)態(tài)撤銷。

裝飾模式和橋接模式的區(qū)別: 兩個(gè)模式都是為了解決過(guò)多子類對(duì)象問(wèn)題。但他們的誘因不一樣。橋接模式是對(duì)象自身現(xiàn)有機(jī)制沿著多個(gè)維度變化,是既有部分不穩(wěn)定。裝飾模式是為了增加新的功能。
注意事項(xiàng):可代替繼承。


實(shí)現(xiàn)

學(xué)習(xí)就是一種裝飾器模式(假設(shè)學(xué)到的知識(shí)不會(huì)忘記),我們不斷的學(xué)習(xí)就是不斷的給被裝飾類加上新的裝飾器。

步驟一:

創(chuàng)建學(xué)習(xí)接口(Learn):

/**
 * @see 具體學(xué)習(xí)的技能(這里作用為輸出自己學(xué)到的技能)
 * @author Thornhill
 *
 */
public interface Learn {
    public void learnSkills();
}

步驟二:

創(chuàng)建具體實(shí)現(xiàn)學(xué)習(xí)接口的學(xué)生(Student):

/**
 * @see 實(shí)現(xiàn)了學(xué)習(xí)接口的學(xué)生,這里是被修飾者的角色
 * @author Thornhill
 *
 */
public class Student implements Learn {

    private String name;

    public Student(String name) {
        this.name = name;
    }

    @Override
    public void learnSkills() {
        System.out.println(name + "學(xué)會(huì)了技能:");
    }

}

步驟三:

創(chuàng)建裝飾角色(Skills):

/**
 * @see 裝飾者的基類,持有一個(gè)學(xué)習(xí)者對(duì)象,被裝飾時(shí)共享一個(gè)學(xué)習(xí)對(duì)象
 * @author Thornhill
 *
 */
public class Skills implements Learn {
    private Learn learner;

    public Skills(Learn learner) {
        this.learner = learner;
    }

    @Override
    public void learnSkills() {
        if (learner != null) {
            learner.learnSkills();
        }

    }

}

步驟四:

創(chuàng)建實(shí)際修飾角色(CSkills):

/**
 * @see 具體修飾者角色,最高層繼承于修飾者(Sills),為了給同一個(gè)方法靈活疊加新的方法,多層繼承于自己。
 * @author Thornhill
 *
 */
public class CSkills extends Skills {

    private String skillName;

    public CSkills(Learn learner, String skillName) {
        super(learner);
        this.skillName = skillName;
    }

    @Override
    public void learnSkills() {
        super.learnSkills();
        System.out.println("    " + skillName);
    }

}

步驟五:

測(cè)試功能:

public class DecoratorPatternDemo {

    public static void main(String[] args) {
        // 創(chuàng)建學(xué)生“小明”
        Learn xiaoming = new Student("小明");
        // 創(chuàng)建修飾者“skills”
        Skills skills = new Skills(xiaoming);
        // 多層修飾skill
        // 即模擬小明多次學(xué)習(xí)新技能
        skills = new CSkills(skills, "Java");
        skills = new CSkills(skills, "Python");
        skills = new CSkills(skills, "Hadoop");
        // 輸出小明的技能
        skills.learnSkills();

    }

}

步驟六:

測(cè)試輸出:

小明學(xué)會(huì)了技能:
    Java
    Python
    Hadoop

結(jié)語(yǔ):

個(gè)人認(rèn)為,裝飾模式即不適用繼承的方式,通過(guò)裝飾者和實(shí)際裝飾者的多次復(fù)合,達(dá)到多次重寫(修飾)需要修飾的方法的目的。

GitHub源代碼

最后編輯于
?著作權(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)容