使用裝飾者模式,可以動態的給一個對象添加一些額外的職責。這適用於,我們只希望給某個對象而不是整個類添加一些功能的場景。通過使用含有某個特定功能的類來“包裹”原始的類,提供給原始的類某些它本身不具備的特性。比如,我們有一杯“茉莉茶”,現在加上一顆“檸檬”,那我們就有了一杯“檸檬茉莉花茶”。“檸檬”作為... ...
裝飾者模式
使用裝飾者模式,可以動態的給一個對象添加一些額外的職責。這適用於,我們只希望給某個對象而不是整個類添加一些功能的場景。通過使用含有某個特定功能的類來“包裹”原始的類,提供給原始的類某些它本身不具備的特性。比如,我們有一杯“茉莉茶”,現在加上一顆“檸檬”,那我們就有了一杯“檸檬茉莉花茶”。“檸檬”作為一個裝飾者,提供了“茉莉茶”本身沒有的清爽口感。當然,這也帶來了一定的負擔,你需要花更多的“錢”。
1. 定義
裝飾者模式動態地將職責附加到對象上。若要擴展功能,裝飾者提供了比繼承更有彈性的解決方案。
2. 為什麼需要
裝飾者提供了繼承更高的靈活性。可以使用繼承來實現將父類的功能添加到子類中,但是這種方式限制了用戶選擇的權利,沒有辦法選擇將父類的哪些功能添加到子類中,只能被動的接受父類所有的功能。作為一個類而言,擁有更多的功能並不一定是件好事。所有的類都不應該試圖成為一個“全棧“。裝飾者模式則剛好提供了用戶選擇的權利,用戶可以”謹小慎微“的選擇自己需要的功能,而不用為自己不需要的功能去買單。
該模式的實現方式,也被它的名字清楚的表達。
裝飾。
3. 實現方案
3.1 實現註意點
- 介面一致性。裝飾對象的介面必須與它所裝飾的類的介面是一致的。體現了“裝飾”過程不能改變對象的“本質”。
- 省略抽象的裝飾者類。
- 改變對象的外殼。裝飾者Decorator可以被看做是一個對象的外殼,它可以改變對象的行為。
3.2 實現代碼
參與者:
- 一個 抽象類Tea ,用於表示茶的最頂層類。
- 一個具體類 JasmineTea ,表示茶的一種,茉莉茶。
- 一個抽象類 TeaDecorator ,表示茶的裝飾者。用於向茶中加入不同的配料。
- 一個具體類 Lemon ,繼承 TeaDecorator ,表示可以向茶中加入的配料,檸檬。
抽象類 Tea 實現代碼如下:
/* 為一個抽象類,所有的茶都需要直接或間接的繼承它 */ public abstract class Tea { private String description = "tea"; public String getDescription() { return description; } }
具體類 JasmineTea 實現代碼如下:
/** * 現在小店只提供一種茶,茉莉茶。 * * 可以向它添加不同的茶調料,搭配不同的口味 */ public class JasmineTea extends Tea { @Override public String getDescription() { return "jasmine tea"; } }
小店剛開業,只提供茉莉花茶,請多擔待。不過,我們提供了配料可以搭配不同的口味。
先需要提供一個 TeaDecorator 的抽象類,它可以提供不同的配料,實現代碼如下:
/* 茶的裝飾者,比如涼茶,檸檬茶等 */ public abstract class TeaDecorator extends Tea{ public abstract String getDescription(); }
接下來,則是本店現今提供的唯一調料,檸檬,實現代碼如下:
/* 這是一個“茶”的裝飾者,表示在茶中加入檸檬 */ public class Lemon extends TeaDecorator { private Tea tea; /** * 註意:這裡需要傳入“一杯茶”,也就是要“被裝飾”的對象 * 這裡的語義:有一杯茶,需要向茶中加入檸檬。 * 理所當然的,檸檬就是一個“裝飾者” */ public Lemon(Tea tea) { this.tea = tea; } public String getDescription() { return "lemon " + tea.getDescription(); } }
好!小店已經準備好了茶,也準備好了調料。那是時候給各位客觀端上一杯沁人心脾的“檸檬茉莉花茶”了,代碼實現如下:
public class App { public static void main(String[] args) { Tea jasmineTea = new JasmineTea(); // 先沖一杯清香的茉莉茶 Tea lemonJasmineTea = new Lemon(jasmineTea); // 然後向茶中加入一顆檸檬 System.out.println(lemonJasmineTea.getDescription()); // 一杯生津止渴的 “lemon jasmine tea” 就泡好了 } }
端上一杯“檸檬茉莉花茶”,就著網易雲音樂,看著“四人幫”的設計模式,豈不美哉!
4. 總結
裝飾者的主要特點在於在不影響其他對象的情況下,可以動態的給單個對象添加職責。關於這點,我們可以參考JDK中的 java.io 包,它是使用裝飾者模式的典型場景。裝飾者模式有如下優點:
- 相比靜態繼承提供了更大的靈活性。它可以在運行時增加和刪除職責。此外,可以很容易的重覆添加一個特性。
- 避免了在層次結構高層的類有太多的特性。它不在一個類中支持所有的特性,每個裝飾者類可以只有一個特性。可以從簡單的部件複合出複雜的功能。
使用該模式也會引入一些問題:
- 有許多小的對象。過多的對象會使得有些人反感,反正我個人還是挺喜歡小的函數、類、模塊...
裝飾的內涵在於不改變原有本質的前提下提供原來沒有的功能。我們需要區分哪些是需要被裝飾的,而哪些是裝飾者。更多的時候是,我們裝飾著別人,同時又被別人所裝飾。
正所謂:明月裝飾了你的窗子,你裝飾了別人的夢...
好夢!