Java常用設計模式之裝飾者模式

在我們進行Java開發的時候,很多時候我們可能對Java提供給我們的對象不滿意,不能滿足我們的功能。此時我們就想對Java原對象進行增強,能夠實現我們想要的功能就好。

一般來說,實現對象增強有三種方式:

  • 繼 承

    • 繼承父類,子類擴展

  • 裝飾器模式

    • 使用“包裝”的方式來增強對象

  • 代理模式

一:繼承

最簡單的方式就是繼承父類,子類擴展來達到目的。雖然簡單,但是這種方式的缺陷非常大

  • 一、如果父類是帶有數據、信息、屬性的話,那麼子類無法增強。

  • 二、子類實現了之後需求無法變更,增強的內容是固定的。

我們設計一個電話類

public interface Phone {
    void call();

}

此時,我想打電話之前能聽彩鈴,於是我繼承Phone類,實現我想要的功能。

public class MusicPhone implement Phone {
    public MusicPhone(Phone phone){
        super(phone);
    }

    public void listenMusic(){
        System.out.println("繼續跑 帶着赤子的驕傲,生命的閃耀不堅持到底怎能看到,與其苟延殘喘不如縱情燃燒");
    }

    @Override
    public void call() {
        listenMusic();
        super.call();
    }
}

我們的功能就做好了:

 

可是我需求現在又想變了:

  • 我不想聽彩鈴了,只想聽完電話通知一下時間就好了……..(可是我們的通知時間電話類是繼承在聽彩鈴的電話類基礎之上的),,,

  • 我又有可能:我想在聽電話之前報告一下時間,聽完電話聽音樂!…

  • 如果需求變動很大的情況下,而我們又用繼承的方式來實現這樣會導致一種現象:類爆炸(類數量激增)!並且繼承的層次可能會比較多~

所以,我們可以看到子類繼承父類這種方式來擴展是十分侷限的,不靈活的~

因此我們就有了裝飾模式

二:裝飾者模式

1:電話接口

public interface Phone {
    void call();

}

2;具體實現:

public class IphoneX implements Phone {
    @Override
    public void call() {
        System.out.println("打電話給周圍的人關注我");
    }
}

3:換一種實現方式

上面我們已經擁有了一個接口還有一個默認實現。包裝模式是這樣乾的:

首先我們弄一個裝飾器,它實現了接口,以組合的方式接收我們的默認實現類

 

public class PhoneDecorate implements Phone {

    private Phone phone;
    public PhoneDecorate(Phone phone){
        this.phone=phone;
    }
    @Override
    public void call() {
         phone.call();
    }
}

有了裝飾器以後,我們的擴展都可以以裝飾器爲基礎進行擴展,繼承裝飾器來擴展就好了!

我們想要在打電話之前聽音樂

 

public class MusicPhone extends PhoneDecorate {
    public MusicPhone(Phone phone){
        super(phone);
    }

    public void listenMusic(){
        System.out.println("繼續跑 帶着赤子的驕傲,生命的閃耀不堅持到底怎能看到,與其苟延殘喘不如縱情燃燒");
    }

    @Override
    public void call() {
        listenMusic();
        super.call();
    }
}

現在我也想在打完電話後通知當前的時間,於是我們也繼承裝飾類來擴展

// 這裏繼承的是MusicPhone裝飾器類
public class GiveCurrentTimePhone extends PhoneDecorate  {


    public GiveCurrentTimePhone(Phone phone) {
        super(phone);
    }

    // 自定義想要實現的功能:給出當前的時間
    public void currentTime() {
        System.out.println("當前的時間是:" + System.currentTimeMillis());
    }

    // 重寫要增強的方法
    @Override
    public void call() {
        super.call();
        // 打完電話後通知一下當前時間
        currentTime();
    }
}

目前這樣看起來,比我直接繼承父類要麻煩,而功能效果是一樣的….我們繼續往下看~~

此時,我不想在打電話之前聽到彩鈴了,很簡單:我們不裝飾它就好了!

此時,我想在打電話前報告一下時間,在打完電話之後聽彩鈴。

  • 注意:雖然說要改動類中的代碼,但是這種改動是合理的。因爲我定義出的GiveCurrentTimePhone類MusicPhone類本身從語義上就沒有規定擴展功能的執行順序

  • 而繼承不一樣:先繼承Phone->實現MusicPhone->再繼承MusicPhone實現GiveCurrentTimePhone。這是固定的,從繼承的邏輯上已經寫死了具體的代碼,是難以改變的。

三:裝飾者模式講解

可能有的同學在看完上面的代碼之後,還是迷迷糊糊地不知道裝飾模式是怎麼實現“裝飾”的。下面我就再來解析一下:

  • 第一步:我們有一個Phone接口,該接口定義了Phone的功能

  • 第二步:我們有一個最簡單的實現類iPhoneX

  • 第三步:寫一個裝飾器抽象類PhoneDecorate,以組合(構造函數傳遞)的方式接收我們最簡單的實現類iPhoneX。其實裝飾器抽象類的作用就是代理(核心的功能還是由最簡單的實現類iPhoneX來做,只不過在擴展的時候可以添加一些沒有的功能而已)。

  • 第四步:想要擴展什麼功能,就繼承PhoneDecorate裝飾器抽象類,將想要增強的對象(最簡單的實現類iPhoneX或者已經被增強過的對象)傳進去,完成我們的擴展!

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章