經常使用設計模式:裝飾者模式

  今天看了一篇很棒的介紹裝飾者模式的文章,因而就按照以往的慣例,學習了以後手動的碼了這麼一篇隨記記錄本身的體會,而且參考原文的例子,本身手動的實現了一遍整個demo,原文地址爲:http://blog.csdn.net/zhaoyanjun6/article/details/56488020ide

  首先咱們來大致瞭解一下裝飾者模式到底是個什麼東西呢?所謂的裝飾者,能夠參考如今很火的一個遊戲——絕地大逃殺裏頭的槍械自由改裝的概念來解釋裝飾者模式的概念。如今有這麼一把AK47槍,除了槍以外,沒有任何之外的配件,看到人就只能拿着把裸的AK隨便的突突突,碰運氣看看能不能打中人。而忽然該玩家得到了一個八倍瞄準鏡,和一個消聲器,這時候該玩家就能夠把這個瞄準鏡和消聲器安裝到AK上,而後他就能夠用這把AK的八倍鏡去瞄準2000米外的敵人,而後用AK上的消聲器,悄無聲息的擊殺別人。而這時候,這個玩家用膩了AK,因而又把這個瞄準鏡和消聲器安裝到了本身的沙漠飛鷹的手槍上,這時候,這個沙漠飛鷹就具備了和AK的同樣的功能。這個就是咱們所謂的裝飾者模式,經過裝飾器裝飾以後,咱們的目標就會具備一個新的功能。性能

  那麼瞭解了裝飾者模式是什麼以後,它的好處就更一目瞭然了吧?在拓展一個類的功能的時候,一般可使用繼承來實現功能的拓展,若是這些須要拓展的功能的種類很繁多,那麼勢必生成不少子類,增長系統的複雜性,同時,使用繼承實現功能拓展,咱們必須可預見這些拓展功能,這些功能是編譯時就肯定了,是靜態的。而經過裝飾者模式來作這個事情,就能夠完美的解決這些問題。就用咱們剛剛那個例子來講,若是經過繼承來實現的話,那麼勢必AK47下會有這麼些子類,帶瞄準鏡的AK,帶消聲器的AK,帶瞄準鏡和消聲器的AK,這就很蛋疼咯吧?並且若是要用在沙漠飛鷹之上,又要有帶瞄準鏡的沙漠飛鷹子類等,會有無數的子類出現。學習

  二話不說 ,那麼接下來咱們先來看看代碼測試

先看看被裝飾者的代碼:this

public interface Gun {

    void status();
    
}

public class AK47 implements Gun {

    @Override
    public void status() 
    {
        System.out.println("當前AK沒有任何配件");
        
    }
}

public class DesertEagle implements Gun {

    @Override
    public void status() 
    {
        System.out.println("當前沙漠飛鷹沒有任何配件");
        
    }
}

被裝飾者都共同實現了一個叫GUN的接口(AK和沙漠飛鷹都屬於槍,在這個接口下有一個方法叫status表示當前該槍具備什麼配件),接下來看看咱們的裝飾器類:spa

public abstract class GunPart implements Gun {

    Gun gun;
    
    public GunPart(Gun gun) 
    {
        this.gun=gun;
    }
    
    @Override
    public void status() {
        gun.status();
    }
}


public class muffler extends GunPart {

    public muffler(Gun gun) {
        super(gun);
    }

    @Override
    public void status() {
        super.status();
        say();
    }

    public void say()
    {
        System.out.println("該槍有了消聲器");
    }
}

public class telescope extends GunPart {

    
    public telescope(Gun gun) {
        super(gun);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void status() {
        // TODO Auto-generated method stub
        super.status();
        say();
    }
    
    public void say()
    {
        System.out.println("該槍有了瞄準鏡");
    }

}

在裝飾器當中,咱們抽象了這麼一個抽象類叫作GunPart,而不管是消聲器仍是瞄準鏡都是屬於GunPart(槍械配件的一部分)因此都是繼承了這個GunPart,而這個GunPart同時也實現了Gun這個接口,注意這裏是重點,這個GunPart必定也要實現這個Gun接口,不然就沒法實現裝飾器可疊加的效果了。而繼承了GunPart的子類,都會重寫父類的status方法,重寫的內容第一行必定是調用父類的.status方法。而後再加上該子類添加的特點功能,在例子中是say()方法。.net

接下來看看咱們的測試代碼和測試結果:代理

public class test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Gun AK47=new AK47();
        muffler muffler=new muffler(AK47);
        telescope telescope=new telescope(muffler);
        telescope.status();
        
        System.out.println();
        
        Gun DS=new DesertEagle();
        muffler muffler1=new muffler(DS);
        telescope telescope1=new telescope(muffler1);
        telescope1.status();
    }

}
當前AK沒有任何配件
該槍有了消聲器
該槍有了瞄準鏡

當前沙漠飛鷹沒有任何配件
該槍有了消聲器
該槍有了瞄準鏡

這樣,咱們一個完整的裝飾者模式的demo就寫完了,那麼咱們來試着總結一下裝飾者模式的一些重點,首先看看這個繼承和實現關係圖:調試

  • Component抽象構件角色:真實對象和裝飾對象有相同的接口。這樣,客戶端對象就可以以與真實對象相同的方式同裝飾對象交互。用咱們例子裏的話,就是Gun這個接口。
  • ConcreteCompoent 具體構建角色(真實對象):定義一個將要接收附加責任的類。用咱們例子裏的話,就是AK47這個類和沙漠飛鷹這個類。
  • Decorator裝飾角色:持有一個抽象構件的引用。裝飾對象接受全部客戶端的請求,並把這些請求轉發給真實的對象。這樣,就能在真實對象調用先後增長新的功能。例子裏對應的是GunPart這個抽象類。
  • ConcreteDecorate具體裝飾角色:負責給構件對象增長新的功能。對應的就是消聲器和八倍鏡那個類了。

總的來講,裝飾模式下降系統的耦合度,能夠動態的增長或刪除對象的責任(在寫test類的方法的時候,動態的添加或者不添加),並使得須要裝飾的具體構建類和具體裝飾類能夠獨立變化,以便增長新的具體構建類和具體裝飾類。code

優勢

  •  擴展對象功能,比繼承靈活,不會致使類個數急劇增長。
  • 能夠對一個對象進行屢次裝飾,創造出不一樣行爲的組合,獲得功能更增強大的對象。
  • 具體構 件 類和具體裝飾類能夠獨立變化,用戶能夠根據須要本身增長新的 具體構件子類和具體裝飾子類。

缺點

  • 產生不少小對象。大量小的對象佔據內存,必定程度上影響性能。
  • 裝飾模式易出錯,調試排查比較麻煩。

那麼裝飾者模式講到這裏,就差很少。。。。。。。。。。。。。。。殼鬥麻袋~!!!!你看到這裏確定會忽然發覺,誒?這個裝飾者模式怎麼特麼的和靜態代理那麼像啊

1.一樣都是加強類(裝飾器)和目標類(被裝飾者)實現了同一個接口。

2.一樣都是經過加強類(裝飾器)重寫和目標類(被裝飾者)來加強方法。

 

這特麼不是同樣的嘛?

其實我看到這裏的時候,也產生了這麼一個疑問,因而就去查閱了其餘關於代理模式和裝飾者模式,因而獲得瞭如下三點:

1.裝飾器模式關注於在一個對象上動態的添加方法,然而代理模式關注於控制對對象的訪問。

2.裝飾器模式能夠疊加的爲被裝飾者裝飾,而代理不支持多層嵌套。這也是我爲何在前邊「劃重點」的緣由。

好啦,具體的仍是本身體會吧。(其實本身這一塊也還不大會,一塊兒學習咯)

相關文章
相關標籤/搜索