設計模式【8】-- 手工耿教我寫裝飾器模式

秦懷雜貨店發表於2022-01-13

https://markdownpicture.oss-cn-qingdao.aliyuncs.com/blog/設計模式.png

裝飾器模式

前面學習了好幾種設計模式,今天繼續...

裝飾器模式,屬於結構型模式,用來包裹封裝現在的類物件,希望可以在不修改現在類物件和類定義的前提下,能夠擴充物件的功能。

呼叫的時候,使用的是裝飾後的物件,而不是原物件。,提供了額外的功能。

不知道大家有沒有看手工耿的自制鋼琴烤串車視訊【https://www.bilibili.com/vide... 】, 本來是一個鋼琴,但是為了邊彈琴,邊烤串,改造裝飾了一下,變成了特殊的鋼琴,提供了額外的烤串功能。典型的裝飾器模式

目的: 為了靈活的擴充類物件的功能。

主要包括以下幾種角色:

  • 抽象元件(Component): 被裝飾的原始類的抽象,可以是抽象類,亦或是介面。
  • 具體實現類(ConcreteComponent):具體的被抽象的類
  • 抽象裝飾器(Decorator): 通用抽象器
  • 具體裝飾器(ConcreteDecorator):Decorator 的具體實現類,理論上,每個 ConcreteDecorator都擴充套件了Component物件的一種功能。

優缺點

優點:

  • 相對於類繼承,包裹物件更加容易擴充,更加靈活
  • 裝飾類和被裝飾類相互獨立,耦合度比較低
  • 完全遵守開閉原則。

缺點:

  • 包裹物件層級較深的時候,理解難度較大。

實現

先抽閒一個樂器介面類 Instrument

public interface Instrument {
    void play();
}

弄兩種樂器PianoGuitar ,實現樂器介面:

public class Piano implements Instrument{
    @Override
    public void play() {
        System.out.println("手工耿彈奏鋼琴");
    }
}
public class Guitar implements Instrument{
    @Override
    public void play() {
        System.out.println("手工耿彈吉他");
    }
}

不管手工耿要邊彈吉他邊燒烤,還是邊彈鋼琴邊燒烤,還是邊彈鋼琴邊洗澡,不管什麼需求,我們抽象一個裝飾器類,專門對樂器類進行包裝,裝飾。

public class InstrumentDecorator implements Instrument{
    protected Instrument instrument;

    public InstrumentDecorator(Instrument instrument) {
        this.instrument = instrument;
    }

    @Override
    public void play() {
        instrument.play();
    }
}

上面的是抽象的裝飾類,具體裝飾成什麼樣,我們得搞點實際動作,那就搞個燒烤功能。

public class BarbecueInstrumentDecorator extends InstrumentDecorator {
    public BarbecueInstrumentDecorator(Instrument instrument) {
        super(instrument);
    }

    @Override
    public void play() {
        instrument.play();
        barbecue();
    }

    public void barbecue(){
        System.out.println("手工耿在燒烤");
    }
}

測試一下:

public class DecoratorDemo {
    public static void main(String[] args) {
        Instrument instrument = new Piano();
        instrument.play();
        System.out.println("----------------------------------------");
        InstrumentDecorator barbecuePiano = new BarbecueInstrumentDecorator(new Piano());
        barbecuePiano.play();
        System.out.println("----------------------------------------");
        InstrumentDecorator barbecueGuitar = new BarbecueInstrumentDecorator(new Guitar());
        barbecueGuitar.play();
    }
}

測試結果如下,可以看到不裝飾的時候,只能幹一件事,裝飾之後的物件,既可以彈奏樂器,也可以燒烤,不禁感嘆:原來手工耿是設計模式高手:

手工耿彈奏鋼琴
----------------------------------------
手工耿彈奏鋼琴
手工耿在燒烤
----------------------------------------
手工耿彈吉他
手工耿在燒烤

小結一下

設計模式,不是銀彈,只是在軟體工程或者說程式設計中,演變出來的較好實踐。我們不能為了設計模式而設計模式,學習理論只是為了更好的使用它,知道什麼時候應該使用,什麼時候不該使用。

裝飾器模式是為了擴充其功能,但又不破壞原來的結構的前提下做的,其實在Java IO的原始碼裡面有大量使用,比如:

DataInputStream dis = new DataInputStream(
                    new BufferedInputStream(
                            new FileInputStream("test.txt")
                            )
                    );

先把FileInputStream傳遞給BufferedInputStream弄成一個裝飾物件,再把裝飾物件傳遞給DataInputStream,再裝飾一遍。最終,FileInputStream 被包裝成了 DataInputStream,感興趣的同學可以翻一下原始碼。

【作者簡介】
秦懷,公眾號【秦懷雜貨店】作者,技術之路不在一時,山高水長,縱使緩慢,馳而不息。

劍指Offer全部題解PDF

開源程式設計筆記

相關文章