JavaScript设计模式(八)职责链模式 装饰者模式

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

一、职责链模式

1.基本实现

/**
 * 下面,以一个发放奖学金的例子为例,学生的评级为A,发放奖学金1500,评级B,发放1000,评级C,发放500;
 */

//基本实现
let order = function (type) {
    if (type === 'A') {
        return 1500;
    } else if(type === 'B') {
        return 1000;
    } 
    return 500;
}

//职责链模式实现
let orderA = function (type) {
    if (type == 'A') {
        return 1500;
    }
    return orderB(type);
}

let orderB = function (type) {
    if (type === 'B') {
        return 1000;
    }
    return orderC(type);
}

let orderC = function (type) {
    if (type === 'C') {
        return 500;
    }
    throw new Error('参数输入有误')
}

通过以上实现了一个基本的职责链模式,用户可以从职责链的任意结点开始调用,直到请求被传给可以处理请求的结点。但如果之后新增了奖学金金评级,或者需要在评级结点中插入结点,则需要进入原代码中修改代码,这很违反开闭原则,因此对其进行以下修改。

//灵活可拆分的职责链结点
let orderA = function (type) {
    if (type == 'A') {
        console.log(1500);
    } else {
        this.next.passRequest(type);
    }
}

let orderB = function (type) {
    if (type === 'B') {
        console.log(1000);
    } else {
        this.next.passRequest(type);
    }
}

let orderC = function (type) {
    if (type === 'C') {
        console.log(500);
    } else {
        throw new Error('参数输入有误');
    }
}

let Chain = function (fn) {
    this.fn = fn;
    this.next = null;
}

Chain.prototype.setNext = function (next) {
    this.next = next;
}

Chain.prototype.passRequest= function() {
    this.fn.apply(this, arguments);
}

let chainA = new Chain(orderA);
let chainB = new Chain(orderB);
let chainC = new Chain(orderC);

chainA.setNext(chainB);
chainB.setNext(chainC);

chainA.passRequest('B'); //1000

通过以上代码,我们可以灵活的对职责链中的节点进行增删.

2.职责链模式的优缺点

(1)优点
解耦了请求发送者和N个接收者之间的负责关系
链中的节点可以灵活地拆分重组
可以手动指定起始节点
(2)缺点
不能保证某个请求一定会被链中的节点处理
当职责链过长时,会带来一定的性能损耗

二、装饰者模式

在不改变对象自身的基础上,在程序运行期间给对象动态地添加职责。

1.基本的装饰者模式实现

//下面以一个飞机大战游戏为例,飞机一开始默认只能发射普通子弹,二级可以发射导弹,三级可以发射激光炮
let Plane = function () { };

Plane.prototype.fire = function () {
    console.log('发射普通子弹');
}

let MissileDecorator = function (plane) {
    this.plane = plane;
}

MissileDecorator.prototype.fire = function () {
    this.plane.fire();
    console.log('发射导弹');
}

let LaserDecorator = function (plane) {
    this.plane = plane;
}

LaserDecorator.prototype.fire = function () {
    this.plane.fire();
    console.log('发射激光炮');
}

let plane = new Plane;
plane = new MissileDecorator(plane);
plane = new LaserDecorator(plane);

plane.fire(); //发射普通子弹 发射导弹 发射激光炮

在上述代码中,分别创建了两个装饰者类,装饰者类有着和被装饰者同样的方法名称,且装饰者在执行自己本身方法的同时,还会去执行被装饰者的方法。通过这样的方式,可以给对象动态地增加职责,且不会更改对象本身。

2.JavaScript中的装饰者

//在上面的例子中,我们模仿传统面向对对象语言的方式,使用类完成了一个装饰者模式的设计,但是在js中其实并不需要仿照类的模式
let plane = {
    fire: function () {
        console.log('发射普通子弹');
    }
}

let missileDecorator = function () {
    console.log('发射导弹');
}

let laserDecorator = function () {
    console.log('发射激光炮');
}

let fire1 = plane.fire;

plane.fire = function () {
    fire1();
    missileDecorator();
}

let fire2 = plane.fire;

plane.fire = function () {
    fire2();
    laserDecorator();
}

plane.fire();//发射普通子弹 发射导弹 发射激光炮

3.装饰函数

在上述JavaScript方式实现装饰者模式的代码中,我们通过保存原来的fire方法,来达到给fire方法添加新行为的目的,这这方式同样也是一种在开发中比较常用的方式。有时候我们在想给window绑定onload事件时,不确定该事件是否已经被绑定过,那么我们可以在新绑定的事件中,保存原先的window.onload,然后在新的onload函数中执行。
(1)缺点

  • 必须维护中间变量
  • 容易this劫持问题

4.使用AOP装饰函数

//Function.prototype.before方法和Function.prototype.after方法
Function.prototype.before = function (fn) {
    let _self = this;
    return function () {
        fn.apply(this, arguments);
        return _self.apply(this, arguments);
    }
}

Function.prototype.after = function (fn) {
    let _self = this;
    return function () {
        let res = _self.apply(this, arguments);
        fn.apply(this, arguments);
        return res;
    }
}

let func = function (num) {
    console.log(num);
}

func = func.before(function () {
    console.log(1);
}).after(function () {
    console.log(3)
});

func(2); // 1 2 3

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

volit_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值