设计模式之装饰器

517 阅读2分钟

什么是设计模式?为什么要使用设计模式?

设计模式是软件开发过程中的通用解决方案(23种),不是特种语言的,是一种编程思想。

一般来说,在代码设计中,我们应当遵循「多用组合,少用继承」的原则。通过装饰器模式动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活,让代码变得更加优雅。

装饰器

允许向一个对象添加一个新的功能,但不改变原有对象,装饰器使用 @ 作为标识符,被放置在被装饰代码前面。

通俗的讲就是人在不同的季节穿不同的衣服,人就是那个对象,衣服就是装饰器。

image.png

装饰器原始实现

/* 画个圆 */
class Circle {
  //行为画圆
  draw () {
    console.log("画个圆")
  }
}
/**
 * 给圆描个边框(不改变原先的类) 
 * */
class DarwBord {
  constructor (circle) {
    this.circle = circle
  }
  //这其实就是一个装饰器,即实现了画圆又实现描边
  draw () {
    this.circle.draw();
    this.drawBord()
  }
  //行为描边
  drawBord () {
    console.log("画边框");
  }
}

const circle = new Circle()

const drawBoard = new DarwBord(circle)
drawBoard.draw()
装饰器----注解形式(注意:ES6不识别注释装饰 @run ,装饰器是最新的 ECMA 中的一个提案,是一种与类(class)相关的语法,用来注释或修改类和类方法
//装饰器----注解形式
class Boy {
  @run //注解装饰
  speak () {
    console.log('我能唱歌')
  }
}
/** 
 * 装饰器
 * @param target Boy对象
 * @param key 被装饰的方法名
 * @param descriptor 描述对象
*/
function run (target, key, descriptor) {
  console.log(target, key, descriptor)
  console.log("我能跑步")
}

const boy = new Boy()
boy.speak()
装饰器----给方法添加日志
class Math {
  @log //给方法添加日志输出功能
  add (a, b) {
    return a + b
  }
}
function log (target, name, descriptor) {
  const oldValues = descriptor.value; //oldValues其实指的是Math里的add方法
  //重构
  descriptor.value = function () {
    //arguments js内置对象 包括该函数的所有实参
    console.log(`调用${name} 参数:`, arguments)
    //target 作用域
    return oldValues.apply(target, arguments)
  }
  console.log(descriptor)
  return descriptor
}

const math = new Math();
math.add(1, 3)
装饰器----带参数的
class Math {
  @log(100) //给方法添加日志输出功能
  add (a, b) {
    return a + b
  }
}
//日志装饰器
function log (num) { //闭包
  return function (target, name, descriptor) {
    const _num = num || 0;//
    const oldValues = descriptor.value; //oldValues其实指的是Math里的add方法
    //重构
    descriptor.value = function (...arg) {
      arg[0] += _num
      arg[1] += _num
      //arguments js内置对象 包括该函数的所有实参
      console.log(`调用${name} 参数:`, arg)
      //target 作用域
      return oldValues.apply(target, arg)
    }
    console.log(descriptor)
    return descriptor
  }
}


const math = new Math();
console.log(math.add(1, 3))

代码仓库地址gitee.com/wangsf1/dec…