裝飾器模式
前面學習了好幾種設計模式,今天繼續...
裝飾器模式,屬於結構型模式,用來包裹封裝現在的類物件,希望可以在不修改現在類物件和類定義的前提下,能夠擴充物件的功能。
呼叫的時候,使用的是裝飾後的物件,而不是原物件。,提供了額外的功能。
不知道大家有沒有看手工耿的自制鋼琴烤串車視訊【https://www.bilibili.com/vide... 】, 本來是一個鋼琴,但是為了邊彈琴,邊烤串,改造裝飾了一下,變成了特殊的鋼琴,提供了額外的烤串功能。典型的裝飾器模式
目的: 為了靈活的擴充類物件的功能。
主要包括以下幾種角色:
- 抽象元件(
Component
): 被裝飾的原始類的抽象,可以是抽象類,亦或是介面。 - 具體實現類(
ConcreteComponent
):具體的被抽象的類 - 抽象裝飾器(
Decorator
): 通用抽象器 - 具體裝飾器(
ConcreteDecorator
):Decorator
的具體實現類,理論上,每個ConcreteDecorator
都擴充套件了Component
物件的一種功能。
優缺點
優點:
- 相對於類繼承,包裹物件更加容易擴充,更加靈活
- 裝飾類和被裝飾類相互獨立,耦合度比較低
- 完全遵守開閉原則。
缺點:
- 包裹物件層級較深的時候,理解難度較大。
實現
先抽閒一個樂器介面類 Instrument
:
public interface Instrument {
void play();
}
弄兩種樂器Piano
和Guitar
,實現樂器介面:
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
,感興趣的同學可以翻一下原始碼。
【作者簡介】:
秦懷,公眾號【秦懷雜貨店】作者,技術之路不在一時,山高水長,縱使緩慢,馳而不息。