From 2ca71325695ea2770c4b9ea9b935538baa8b1521 Mon Sep 17 00:00:00 2001
From: ascoders <576625322@qq.com>
Date: Sun, 29 Nov 2020 18:04:27 +0800
Subject: [PATCH] 175
---
...50\346\250\241\345\274\217\343\200\213.md" | 104 ++++++++++++++++++
1 file changed, 104 insertions(+)
create mode 100644 "175.\347\262\276\350\257\273\343\200\212\350\256\276\350\256\241\346\250\241\345\274\217 - Decorator \350\243\205\351\245\260\345\231\250\346\250\241\345\274\217\343\200\213.md"
diff --git "a/175.\347\262\276\350\257\273\343\200\212\350\256\276\350\256\241\346\250\241\345\274\217 - Decorator \350\243\205\351\245\260\345\231\250\346\250\241\345\274\217\343\200\213.md" "b/175.\347\262\276\350\257\273\343\200\212\350\256\276\350\256\241\346\250\241\345\274\217 - Decorator \350\243\205\351\245\260\345\231\250\346\250\241\345\274\217\343\200\213.md"
new file mode 100644
index 00000000..3dfa97fa
--- /dev/null
+++ "b/175.\347\262\276\350\257\273\343\200\212\350\256\276\350\256\241\346\250\241\345\274\217 - Decorator \350\243\205\351\245\260\345\231\250\346\250\241\345\274\217\343\200\213.md"
@@ -0,0 +1,104 @@
+# Decorator(装饰器模式)
+
+Decorator(装饰器模式)属于结构型模式,是一种拓展对象额外功能的设计模式,别名 `wrapper`。
+
+**意图:动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator 模式相比生成子类更为灵活。**
+
+## 举例子
+
+如果看不懂上面的意图介绍,没有关系,设计模式需要在日常工作里用起来,结合例子可以加深你的理解,下面我准备了三个例子,让你体会什么场景下会用到这种设计模式。
+
+### 相框
+
+照片 + 相框 = 带相框的照片,这背后就是一种装饰器模式:照片具有看的功能,相框具有装饰功能,在你看照片的基础上,还能看到精心设计的相框,增加了美感,同时相框还可以增加照片的保存时间与安全性。
+
+相框与照片是一种组合关系,任何照片都可以放到相框中,而不是每个照片生成一个特定的相框,显然,组合的方式更加灵活。
+
+### 带有缓存的文件读写
+
+假设我们有一个类 `FileIO` 用来读写文件,但是没有缓存能力,此时是新建一个 `CachedFileIO` 子类好,还是创建一个 `CachedIO`?
+
+一眼看上去好像 `CachedFileIO` 用起来更方便,而 `CachedIO` 的用法是 `new CachedIO(new FileIO())` 稍微麻烦一些,但如果我们增加一个网络读写类 `NetworkIO`,一个数据库读写类 `DBIO` 呢?
+
+显然,继承的方式会使子类数量极速膨胀,而组合的方式则非常灵活,生成一个支持缓存的网络读写器,只需要 `new CachedIO(new NetworkIO())` 即可,这就是组合灵活的地方。
+
+当然,为了实现这个能力,`CachedIO` 需要与 `FileIO`、`CachedFileIO`、`CachedIO` 继承自同一个类,具备相同的接口。
+
+### 搭建平台的组件 wrapper
+
+装饰器模式别名也叫 `wrapper`,`wrapper` 也经常在前端搭建场景中遇到,当搭建平台加载一个组件时,希望拓展其基础能力,一般会使用 `wrapper` 层对组件进行嵌套,`wrapper` 层就是在不改变 API 的基础上,对第三方组件进行增强。
+
+## 意图解释
+
+**意图:动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator 模式相比生成子类更为灵活。**
+
+不同于继承,组合可以在运行时进行,所以称之为 “动态添加”,这里的 “额外职责” 泛指一切功能,比如在按钮点击时进行一些 log 日志的打印,在绘制 text 文本框时,额外绘制一个滚动条和边框等等。
+
+“就增加功能来说,Decorator 模式相比生成子类更为灵活” 这句话的含义是,组合比继承更灵活,当可拓展的功能很多时,继承方案会产生大量的子类,而组合可以提前写好处理函数,在需要时动态构造,显然是更灵活的。
+
+## 结构图
+
+
+
+`ConcreteComponent` 指的是需要被装饰的组件,可以看到,装饰器 `Decorator` 与他都继承同一个类,这样能保证 API 的一致,才保证无论装饰多少层,始终符合 `Component` 类型。
+
+装饰器如果有多种,就要将 `Decorator` 申明为抽象类,`ConcreteDecoratorA`、`ConcreteDecoratorB` 分别实现它们,如果只有一种装饰器,可以退化到 `Decorator` 自身就是一种实现。
+
+## 代码例子
+
+下面例子使用 typescript 编写。
+
+```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()
+```
+
+其实方法很简单,通过组合,我们得到了一个能力更强的组件,而实现的方式就是利用构造函数保存组件实例,并在复写函数时,增加一些增强实现。
+
+## 弊端
+
+装饰器的问题也是组合的问题,过多的组合会导致:
+
+- 组合过程的复杂,要生成过多的对象。
+- 包装器层次增多,会增加调试成本,我们比较难追溯到一个 bug 是在哪一层包装导致的。
+
+## 总结
+
+装饰器模式是非常常用的模式,Decorator 是一个透明的包装,只要保证包装的透明性,就可以最大限度发挥装饰器模式的优势。
+
+最后总结一个装饰器应用图:
+
+
+
+> 讨论地址是:[精读《设计模式 - Decorator 装饰器模式》· Issue #286 · dt-fe/weekly](https://github.com/dt-fe/weekly/issues/286)
+
+**如果你想参与讨论,请 [点击这里](https://github.com/dt-fe/weekly),每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。**
+
+> 关注 **前端精读微信公众号**
+
+
+
+> 版权声明:自由转载-非商用-非衍生-保持署名([创意共享 3.0 许可证](https://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh))