1.什么是装饰器模式

Decorator Design Pattern:
当我们拍了一张照片准备发朋友圈时,我们会选择给照片加上滤镜。同一张照片、不同的滤镜组合起来就会有不同的体验。这实际上就是装饰者模式:是通过滤镜装饰了照片。在不改变对象(照片)的情况下,动态的为其添加功能(滤镜),而且通过不同的装饰器组合(不同的滤镜组合),可以达到叠加的效果

需要注意的是:由于 JavaScript 语言动态的特性,我们很容易就能改变某个对象。但是我们要尽量避免直接改写某个函数,这违反了开闭原则。js里函数也是对象因此js中的装饰器模式,实际上是装饰的是函数。

2.使用AOP装饰函数

回到上面的例子,因为装饰的是函数,因此改为给拍照片这个动作(而不是照片)添加滤镜功能。

  1. // AOP函数
  2. const after = function(fn, afterFn) {
  3. return function (...args) {
  4. const ret = fn.apply(this, args);
  5. afterFn.apply(this, args);
  6. return ret;
  7. }
  8. }
  9. // 原函数
  10. const takePhoto = function(){
  11. console.log('拍照片');
  12. }
  13. // 装饰函数
  14. const addFilter = function(){
  15. console.log('添加滤镜');
  16. }
  17. takePhoto = after(takePhoto, addFilter);
  18. takePhoto();

3.基于类的原型对象装饰类里的方法

  1. /**
  2. *
  3. * @param {*} target 类
  4. * @param {*} action 类里的方法名
  5. * @param {*} afterFn 装饰函数
  6. */
  7. function after(target, action, afterFn) {
  8. oldAction = target.prototype[action];
  9. if (oldAction) {
  10. target.prototype[action] = function (...args) {
  11. const ret = oldAction.apply(this, args);
  12. afterFn.apply(this, args);
  13. return ret;
  14. }
  15. }
  16. }
  17. class PhotoUtils {
  18. takePhoto() {
  19. console.log('拍照片');
  20. }
  21. }
  22. function addFilter() {
  23. console.log('添加滤镜')
  24. }
  25. const pu = new PhotoUtils();
  26. after(PhotoUtils, 'takePhoto', addFilter);
  27. pu.takePhoto();

注意:装饰一个类本质上还是在装饰类里面的方法。

4.ES和TS中的装饰器

目前Decorator在语言里还处于提案阶段,想用但不敢用啊

参考文献
https://mp.weixin.qq.com/s/WcoX4H4LLgyvr8ELxcE6FQ
《JavaScript设计模式和开发实践》