设计模式-javascript实现【装饰者模式】

定义:给对象动态地增加职责的方式称为装饰者模式,装饰者模式能够在不改变对象自身的基础上,在程序运行
期间给对象动态地添加职责。

从功能上而言,装饰器能很好地描述这个模式,但从结构上看,包装器的说法更加贴切。装饰者模式将一个对象
嵌入另一个对象之中,实际上相当于这个对象被另一个对象包装起来,形成一条包装链。请求随着这条链条依次
传递到所有的对象,每个对象都有处理这条请求的机会。

1. 模拟传统面向对象的装饰者模式

class Plane {
  fire() {
    console.log('fire the bullet');
  }
}
class Missile {
  constructor(plane) {
    this.plane = plane;
  }
  fire () {
    this.plane.fire();
    console.log('fire the Missile');
  }
}
class Atom {
  constructor(plane) {
    this.plane = plane;
  }
  fire() {
    this.plane.fire();
    console.log('fire the Atom');
  }
}

let plane = new Plane();
plane = new Missile(plane);
plane = new Atom(plane);
// 依次输出:fire the bullet, fire the Missile, fire the Atom
plane.fire();

2. 使用重写对象方法的方式实现装饰者模式

const plane = {
  fire: () => {
    console.log('fire the bullet');
  }
};
const fireMissile = () => {
  console.log('fire the Missile');
};

const fireAtom = () => {
  console.log('fire the Atom');
};

const fireBullet = plane.fire;
plane.fire = () => {
  fireBullet();
  fireMissile();
};
const fireBulletAndMissile = plane.fire;

plane.fire = () => {
  fireBulletAndMissile();
  fireAtom();
};

plane.fire();

3. 使用AOP装饰函数

  • 通过在函数原型上增加装饰方法
// 前置装饰
Function.prototype.before = function (beforefn){
  const self = this;
  return function() {
    beforefn.apply(this, arguments);
    return self.apply(this, arguments);
  };
}

// 后置装饰
Function.prototype.after = function (afterfn){
  const self = this;
  return function() {
    const res = self.apply(this, arguments);
    afterfn.apply(this, arguments);
    return res;
  };
}

// 测试装饰函数
function test(){
  console.log(0);
}
function test1(){
  console.log(1);
}
function test2() {
  console.log(2);
}

test.before(test1).before(test2)(); // 2, 1, 0
test.after(test1).after(test2)(); // 2, 1, 0
  • 通过高阶函数的方式实现装饰模式
// fn为原函数,beforefn为装饰函数, 生成的装饰后的函数其内部返回原函数执行后的值
// 前置装饰
const before = (fn, beforefn) => (...args) => {
  beforefn(...args);
  return fn(...args);
}
// 后置装饰
const after  = (fn, afterfn) => (...args) => {
  const res = fn(...args);
  afterfn(...args);
  return res;
}

const test = () => console.log(0);
const test1 = () => console.log(1);
const test2 = () => console.log(2);
before(before(test, test1), test2)();
after(after(test, test1), test2)();
posted @ 2023-03-09 10:56  箫笛  阅读(71)  评论(0编辑  收藏  举报