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 许可证)