掌握設計模式之裝飾者模式

前言

當應用開發中,咱們要爲一個對象在原有功能上進行擴展加強時,每每採用繼承的方式,而繼承過多時就會使得功能類更加複雜,不利於維護,而設計模式中裝飾者模式能夠幫助咱們更好對應這種場景,裝飾者模式能夠作到讓對象可以動態地進行功能擴展,而不影響其餘對象. 那究竟它是如何實現的呢,又如何實際應用呢,就讓咱們一塊兒來學習下這個模式吧。html

模式定義

裝飾者模式屬於結構型設計模式,首先咱們先了解下裝飾者模式的定義。java

In object-oriented programming, the decorator pattern is a design pattern that allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class. The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern.

簡而言之, 裝飾者模式就是動態地爲一個對象擴展額外的功能,不管是動態仍是靜態,都不影響相同類的其餘對象的行爲, 這樣使得對象在運行時更加靈活。設計模式

裝飾者實現的方式一般爲組合或者繼承,可讓客戶端根據需求進行對應的裝飾,來達到功能增長的目標。爲了簡化理解,裝飾者模式中裝飾一詞其實就是給原來的對象添加額外功能。api

模式結構

接下來咱們看下裝飾者模式的層次結構和主要角色.oracle

image-20181105081809413

  • Component 抽象組件,最原始,核心的對象,一般爲接口或者抽象類.
  • ConcreteComponent 具體組件,對 Component 的實現,也是須要裝飾的對象.
  • Decorator 裝飾者, 一般爲抽象組件的抽象實現, 它的屬性必定有私有變量指向 Component.
  • ConcreteDecorator 具體裝飾對象,是 Decorator 的具體實現, 用於將原始,核心的方法裝飾加強的類.

從圖中看到,接口 Component 會有對應的實現類 ConcerateComponent,要對具體實現類進行功能加強,就須要對應的具體裝飾者 ConcreteDecorator ,它經過內部引用 Component 類型的 ConcerateComponent 對象 ,在接口方法的默認實現上,容許添加額外的邏輯和功能代碼。ide

模式實現

如今咱們用喝咖啡的例子來實現下裝飾者模式,假設咱們要買一杯咖啡,須要加糖,加奶,而什麼都不加的咖啡與加奶,加糖的價格都不同,咱們就要計算調製一杯加糖加奶的咖啡須要花費多少錢。微服務

這裏咖啡就是咱們的具體組件 ConcerateComponent, 奶和糖就是具體裝飾對象 ConcreteDecorator。 爲了簡單,咱們先建立一個Component接口類 Drink, 定義兩個方法用來得到價格和描述:oop

接着,建立一個 ConcreteComponentCoffee 實現 Drink 接口.post

如今就須要一個抽象類 DrinkDecorator,用於擴展實現功能加強.
學習

而後就是實現具體裝飾對象 MilkSugar.

最後客戶端實現製做咖啡的動做:

下圖爲示例的類圖:

能夠從上面例子看出,經過添加不一樣的材料,價格不一樣,而且描述信息也不同,而且添加順序能夠動態改變,甚至不添加,讓對象變得十分靈活, 這就是裝飾者模式的精髓所在。

模式使用場景

裝飾者模式一樣大量應用在 JDK 源碼中,咱們常常能夠看到:

裝飾者模式可讓程序中對象在運行時中進行功能的加強和移除,而且採用更靈活的組合方式來進行擴展。

模式的得與失

優勢:

  • 在不影響其餘對象的狀況下,動態爲單個對象新增功能。
  • 裝飾類與被裝飾類 (ConcreteComponent) 相互獨立,互不耦合,易於擴展。
  • 代替繼承方式的功能實現,減小繼承類的存在。

缺點:

  • 裝飾層次過多時會讓被裝飾的對象更復雜,不容易理解,好比使用 Java I/O 的 DataInputStream 對象讀取數據爲 Java 基本類型值時會這樣使用:

    DataInputStream is = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
  • 程序中如有太多的裝飾類,理解和使用上略有難度。

結語

掌握裝飾者模式的精髓在於經過一層層的包裝,讓原來對象的功能更增強大,且包裝過程是動態的,靈活能夠移除的,到最後仍是會調用到原對象最原始的功能。

參考

推薦閱讀

相關文章
相關標籤/搜索