- 引言
- 裝飾器模式
- 具體實例
- 共有接口類
- 具體被裝飾類
- 抽象裝飾器類
- 具體裝飾器類
- 測試
- 裝飾器模式的實際應用
- Java I/O 體系
- 游戲開發中的角色裝備系統
- 總結
引言
在生活中,我們都知道一句話,“人靠衣裝馬靠鞍”,如果想要讓自己在別人眼里看起來更加好看,更加豐富多彩,就得要學會打扮自己,為自己化妝,為自己穿好看的衣服,學會了打扮的本領,那么我們就可以輕松應對不同場合的需求。無論是日常通勤的簡約風,還是晚宴的華麗造型,我們只需在“基礎自我”上疊加不同的裝飾元素,而無需改變本質——這種靈活性和可擴展性,恰恰是裝飾器模式(Decorator Pattern) 在軟件設計中的精髓。
想象一下,我們在實際生活中,是不是如果當前的臉上瑕疵較多,就使用素顏霜遮蓋一下,當前的皮膚太黑,也可以通過化妝技術變白。穿衣更是如此,我們可以選擇穿簡約風格的衣服,在得知今晚要參加晚宴后,還可以換上一套隆重的禮服。這些操作都不需要我們變成一個新的人(繼承的方法),只需要我們使用一下化妝或者是換裝的方法就可以(裝飾器的方法)。
本文通過對一個男孩打扮和換裝的例子,來深入了解裝飾器模式。
裝飾器模式
裝飾器模式是一個結構性設計模式,允許在不修改原有類的情況下,為對象動態添加新功能,而不會影響其他對象。通過將對象放入包含行為的特殊封裝對象中來為原對象綁定新的行為。針對目標方法進行增強,提供新的功能或者額外的功能。也就是例子中的我們把需要打扮的男孩放到化妝臺前或者是衣柜前,然后這個男孩回來的時候就是一個打扮過的了,比原來更加豐富多彩。
首先看一下裝飾器模式的四大核心組件:
Component: 所有可以被裝飾的類要繼承的接口,同時,裝飾器類也要繼承該接口,這樣可以保證裝飾前的對象和經過裝飾后返回的對象是同一個類型。
ConcreteComponent: 具體要裝飾的類,實現Component接口,實現被裝飾前的方法。
AbstractDecorator: 抽象裝飾器類,同樣實現AbstractDecorator接口,為什么要有這個抽象類呢?其實就是可以在這個抽象類中提前把被裝飾的對象原始的功能實現,這樣具體的裝飾器類就不用每個都重復實現原本被裝飾前的對象的功能了,只需要關注如何裝飾它。
ConcreteDecorator: 具體的裝飾器類,繼承抽象裝飾器類,它需要裝飾的那個對象的原來的方法已經在抽象裝飾器中實現了,所以這個類只需要關注需要對被裝飾的類做出哪些裝飾就行了。
具體實例
本文設計的例子是對一個男孩進行打扮,通過化妝臺(化妝裝飾器 MakeupDecorator)和衣帽間(DressupSimpleDecorator 和 DressupGrandDecorator )對男孩進行兩次裝飾,最終男孩原本的模樣(方法)變成裝飾后的模樣。
共有接口類
所有可以被裝飾的類都要繼承這個接口。
//可以進行裝飾需要滿足的接口
interface PersonComponent{public String getFace();public String getColor();public String getDressed();
}
具體被裝飾類
男孩需要被打扮,所以它實現上面的WaitForDecorator接口。
//等待被裝飾的類
class Boy implements PersonComponent{String face;String color;String dress;@Overridepublic String getFace() {return "ugly";}@Overridepublic String getColor() {return "black";}@Overridepublic String getDressed() {return "naked";}
}
抽象裝飾器類
所有的具體裝飾器類都要繼承該接口,可以避免重復的代碼多次編寫,將需要被裝飾的對象在這個抽象裝飾器類中將原本的功能實現一遍,這樣具體裝飾器類就只需要關注具體需要裝飾的功能了。
//裝飾器基類
abstract class PersonDecorator implements PersonComponent{private People people;public PeopleDecorator(People people){this.people=people;}@Overridepublic String getFace(){return people.getFace();}@Overridepublic String getColor(){return people.getColor();}@Overridepublic String getDressed(){return people.getDressed();}
}
具體裝飾器類
化妝裝飾器::
class MakeupDecorator extends PersonDecorator{public MakeupDecorator(People people) {super(people);}@Overridepublic String getFace(){return "make ugly to pretty";}@Overridepublic String getColor(){return "make black to white";}
}
簡約風衣著裝飾器:
class DressupSimpleDecorator extends PersonDecorator{public DressupSimpleDecorator(People people) {super(people);}public String getDressed(){return "wearing simple cloth";}
}
宴會衣著裝飾器:
class DressupGrandDecorator extends PersonDecorator{public DressupGrandDecorator(People people) {super(people);}public String getDressed(){return "wearing grand cloth";}}
測試
public static void main(String[] args) {PersonComponent boy =new Boy();//男孩先穿了簡約衣服打算出門吃海底撈boy = new DressupSimpleDecorator(boy);//男孩簡單地化了個妝boy = new MakeupDecorator(boy);//男孩突然被通知需要參加一場宴會,就換上了華麗的衣服。boy = new DressupGrandDecorator(boy);System.out.println(boy.getColor());System.out.println(boy.getFace());System.out.println(boy.getDressed());}
運行結果如下:
make black to white
make ugly to pretty
wearing grand cloth
可以看見男孩化了妝并且變得漂亮了,最后穿上的是后來穿的華麗衣服。
裝飾器模式的實際應用
下面列舉了幾個典型的應用場景:
Java I/O 體系
Java 的 I/O 類庫大量使用了裝飾器模式,例如 BufferedReader、InputStreamReader、FileInputStream 等,允許開發者通過不同的裝飾器動態增強流的功能。
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("data.txt")));
這里,BufferedReader 作為裝飾器,增強了 InputStreamReader,提供了緩存功能以提高讀取效率。其中他們的共同接口是Reader。
游戲開發中的角色裝備系統
在游戲開發中,角色裝備(如盔甲、武器)通常使用裝飾器模式。例如,一個基礎角色可以通過不同裝備來增強屬性,如增加攻擊力、防御力等。
Character warrior = new Warrior();
warrior = new ArmorDecorator(warrior); // 增加防御
warrior = new SwordDecorator(warrior); // 增加攻擊力
總結
裝飾器模式通過“動態增強”而非“本質改變”的設計理念,為軟件設計提供了高度的靈活性和可擴展性。本文以生活中“換裝打扮”的生動場景為引,巧妙類比了裝飾器模式的核心思想——在不修改對象自身的基礎上,通過層層疊加裝飾器來擴展功能。
核心價值體現:
靈活組合,動態擴展
如同男孩可根據場合自由切換妝容和服飾,裝飾器模式允許在運行時動態添加或替換功能。例如,先穿簡約服裝,再化妝,最后換宴會禮服,每一步裝飾都獨立且可逆,避免繼承帶來的僵化性。
職責分離,結構清晰
通過抽象裝飾器(PeopleDecorator)封裝原始對象,將核心功能(getColor())與裝飾邏輯(美白、換裝)解耦。具體裝飾器僅關注自身新增功能(MakeupDecorator專注美化膚色),代碼可讀性和維護性顯著提升。
遵循開閉原則
新增裝飾器(添加“配飾裝飾器”)無需修改現有代碼,只需繼承抽象裝飾器即可。這種設計支持系統的漸進式擴展,降低耦合度,符合“對擴展開放,對修改關閉”的原則。
實踐啟示:
裝飾器模式尤其適用于需動態、透明地擴展對象功能的場景。例如,Java I/O流中BufferedReader對FileReader的增強,或Web請求處理中的中間件鏈式調用。本文的男孩換裝案例直觀展現了裝飾器的鏈式調用特性——每次裝飾均基于前一步的結果,最終形成功能疊加或覆蓋的效果(最后一次換裝決定最終衣著)。
總之,裝飾器模式如同為對象穿上“功能外衣”,讓代碼在保持簡潔的同時,具備應對復雜需求的優雅擴展能力,是提升系統設計彈性的重要工具。