Decorator(裝飾器模式)屬於結構型模式,是一種拓展對象額外功能的設計模式,別名 wrapper
。前端
意圖:動態地給一個對象添加一些額外的職責。就增長功能來講,Decorator 模式相比生成子類更爲靈活。git
若是看不懂上面的意圖介紹,沒有關係,設計模式須要在平常工做裏用起來,結合例子能夠加深你的理解,下面我準備了三個例子,讓你體會什麼場景下會用到這種設計模式。github
照片 + 相框 = 帶相框的照片,這背後就是一種裝飾器模式:照片具備看的功能,相框具備裝飾功能,在你看照片的基礎上,還能看到精心設計的相框,增長了美感,同時相框還能夠增長照片的保存時間與安全性。typescript
相框與照片是一種組合關係,任何照片均可以放到相框中,而不是每一個照片生成一個特定的相框,顯然,組合的方式更加靈活。數據庫
假設咱們有一個類 FileIO
用來讀寫文件,可是沒有緩存能力,此時是新建一個 CachedFileIO
子類好,仍是建立一個 CachedIO
?設計模式
一眼看上去好像 CachedFileIO
用起來更方便,而 CachedIO
的用法是 new CachedIO(new FileIO())
稍微麻煩一些,但若是咱們增長一個網絡讀寫類 NetworkIO
,一個數據庫讀寫類 DBIO
呢?緩存
顯然,繼承的方式會使子類數量極速膨脹,而組合的方式則很是靈活,生成一個支持緩存的網絡讀寫器,只須要 new CachedIO(new NetworkIO())
便可,這就是組合靈活的地方。安全
固然,爲了實現這個能力,CachedIO
須要與 FileIO
、CachedFileIO
、CachedIO
繼承自同一個類,具有相同的接口。微信
裝飾器模式別名也叫 wrapper
,wrapper
也常常在前端搭建場景中遇到,當搭建平臺加載一個組件時,但願拓展其基礎能力,通常會使用 wrapper
層對組件進行嵌套,wrapper
層就是在不改變 API 的基礎上,對第三方組件進行加強。網絡
意圖:動態地給一個對象添加一些額外的職責。就增長功能來講,Decorator 模式相比生成子類更爲靈活。
不一樣於繼承,組合能夠在運行時進行,因此稱之爲 「動態添加」,這裏的 「額外職責」 泛指一切功能,好比在按鈕點擊時進行一些 log 日誌的打印,在繪製 text 文本框時,額外繪製一個滾動條和邊框等等。
「就增長功能來講,Decorator 模式相比生成子類更爲靈活」 這句話的含義是,組合比繼承更靈活,當可拓展的功能不少時,繼承方案會產生大量的子類,而組合能夠提早寫好處理函數,在須要時動態構造,顯然是更靈活的。
ConcreteComponent
指的是須要被裝飾的組件,能夠看到,裝飾器 Decorator
與他都繼承同一個類,這樣能保證 API 的一致,才保證不管裝飾多少層,始終符合 Component
類型。
裝飾器若是有多種,就要將 Decorator
申明爲抽象類,ConcreteDecoratorA
、ConcreteDecoratorB
分別實現它們,若是隻有一種裝飾器,能夠退化到 Decorator
自身就是一種實現。
下面例子使用 typescript 編寫。
`class Component {
// 具備點擊事件
public onClick = () => {}
}
class Decorator extends Component {
private _component
constructor(component) {
this._component = component
}
public onClick = () => {
log('打點')
this._component.onClick()
}
}
const component = new Component()
// 一個普通的點擊
component.onClick()
const wrapperComponent = new Decorator(component)
// 一個具備打點功能的點擊
wrapperComponent.onClick()
`
其實方法很簡單,經過組合,咱們獲得了一個能力更強的組件,而實現的方式就是利用構造函數保存組件實例,並在複寫函數時,增長一些加強實現。
裝飾器的問題也是組合的問題,過多的組合會致使:
裝飾器模式是很是經常使用的模式,Decorator 是一個透明的包裝,只要保證包裝的透明性,就能夠最大限度發揮裝飾器模式的優點。
最後總結一個裝飾器應用圖:
討論地址是: 精讀《設計模式 - Decorator 裝飾器模式》· Issue #286 · dt-fe/weekly
若是你想參與討論,請 點擊這裏,每週都有新的主題,週末或週一發佈。前端精讀 - 幫你篩選靠譜的內容。
關注 前端精讀微信公衆號
版權聲明:自由轉載-非商用-非衍生-保持署名( 創意共享 3.0 許可證)