設計模式(七)裝飾模式

1.裝飾模式簡介

裝飾模式介紹

裝飾模式是結構型設計模式之一,不必改變類文件和使用繼承的情況下,動態地擴展一個對象的功能,是繼承的替代方案之一。它是通過創建一個包裝對象,也就是裝飾來包裹真實的對象。

定義

動態地給一個對象添加一些額外的職責,就增加功能來說,裝飾模式比生成子類更爲靈活。

裝飾模式結構圖

這裏寫圖片描述

  • Component:抽象組件,給對象動態的添加職責。
  • ConcreteComponent:組件具體實現類。
  • Decorator:抽象裝飾者,繼承Component,從外類來拓展Component類的功能,但對於Component來說無需知道Decorator的存在。
  • ConcreteDecorator:裝飾者具體實現類。

2.裝飾模式的簡單實現

裝飾模式在現實生活中有很多例子,比如給一個人穿上各種衣服,給一幅畫塗色上框等等,這次我要舉得例子有些不同,舉一個武俠修煉武功的例子:楊過本身就會全真劍法,有兩位武學前輩洪七公和歐陽鋒分別傳授楊過打狗棒法和蛤蟆功,這樣楊過除了會全真劍法還會打狗棒法和蛤蟆功。

抽象組件(Component)

作爲武俠肯定要會使用武功的,我們先定義一個武俠的抽象類,裏面有使用武功的抽象方法:

public abstract class Swordsman {
    /**
     * Swordsman武俠有使用武功的抽象方法
     */
    public abstract void attackMagic();
}

組件具體實現類(ConcreteComponent)

被裝飾的具體對象,在這裏就是被教授武學的具體的武俠,他就是楊過,楊過作爲武俠當然也會武學,雖然不怎麼厲害:

public class YangGuo extends Swordsman{
    @Override
    public void attackMagic() {
        //楊過初始的武學是全真劍法
        System.out.println("楊過使用全真劍法");
    }
}

抽象裝飾者(Decorator)

抽象裝飾者保持了一個對抽象組件的引用,方便調用被裝飾對象中的方法。在這個例子中就是武學前輩要持有武俠的引用,方便教授他武學並“融會貫通”:

public abstract class Master extends Swordsman{
    private Swordsman mSwordsman;

    public Master(Swordsman mSwordsman){
        this.mSwordsman=mSwordsman;
    }
    @Override
    public void attackMagic() {
        mSwordsman.attackMagic();
    }
}

裝飾者具體實現類(ConcreteDecorator)

這個例子中用兩個裝飾者具體實現類,分別是洪七公和歐陽鋒,他們負責來傳授楊過新的武功:

public class HongQiGong extends Master {
    public HongQiGong(Swordsman mSwordsman) {
        super(mSwordsman);
    }
    public void teachAttackMagic(){
        System.out.println("洪七公教授打狗棒法");
        System.out.println("楊過使用打狗棒法");
    }
    @Override
    public void attackMagic() {
        super.attackMagic();
        teachAttackMagic();
    }
}
public class OuYangFeng extends Master {
    public OuYangFeng(Swordsman mSwordsman) {
        super(mSwordsman);
    }
    public void teachAttackMagic(){
        System.out.println("歐陽鋒教授蛤蟆功");
        System.out.println("楊過使用蛤蟆功");
    }
    @Override
    public void attackMagic() {
        super.attackMagic();
        teachAttackMagic();
    }
}

客戶端調用

經過洪七公和歐陽鋒的教導,楊過除了初始武學全真劍法又學會了打狗棒法和蛤蟆功:

public class Client {
    public static void main(String[] args){
        //創建楊過
        YangGuo mYangGuo=new YangGuo();
        //洪七公教授楊過打狗棒法,楊過會了打狗棒法
        HongQiGong mHongQiGong=new HongQiGong(mYangGuo);
        mHongQiGong.attackMagic();

        //歐陽鋒教授楊過蛤蟆功,楊過學會了蛤蟆功
        OuYangFeng mOuYangFeng=new OuYangFeng(mYangGuo);
        mOuYangFeng.attackMagic();
    }
}

3.裝飾模式的優缺點和使用場景

優點

  • 通過組合而非繼承的方式,動態的來擴展一個對象的功能,在運行時選擇不同的裝飾器,從而實現不同的行爲。
  • 有效避免了使用繼承的方式擴展對象功能而帶來的靈活性差,子類無限制擴張的問題。
  • 具體組件類與具體裝飾類可以獨立變化,用戶可以根據需要增加新的具體組件類和具體裝飾類,在使用時再對其進行組合,原有代碼無須改變,符合“開閉原則”。

缺點

  • 裝飾鏈不能過長,否則會影響效率。
  • 因爲所有對象都是繼承於Component,所以如果Component內部結構發生改變,則不可避免地影響所有子類(裝飾者和被裝飾者),如果基類改變,勢必影響對象的內部。
  • 比繼承更加靈活機動的特性,也同時意味着裝飾模式比繼承更加易於出錯,排錯也很困難,對於多次裝飾的對象,調試時尋找錯誤可能需要逐級排查,較爲煩瑣,所以只在必要的時候使用裝飾者模式。

使用場景

  • 在不影響其他對象的情況下,以動態、透明的方式給單個對象添加職責。
  • 需要動態地給一個對象增加功能,這些功能可以動態的撤銷。
  • 當不能採用繼承的方式對系統進行擴充或者採用繼承不利於系統擴展和維護時。

4.裝飾模式和代理模式

在上一篇文章設計模式之代理模式中我們講到了代理模式,你會覺得代理模式和裝飾模式有點像,都是持有了被代理或者被裝飾對象的引用。它們兩個最大的不同就是裝飾模式對引用的對象增加了功能,而代理模式只是對引用對象進行了控制卻沒有對引用對象本身增加功能。

發佈了24 篇原創文章 · 獲贊 11 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章