资讯专栏INFORMATION COLUMN

JS设计模式--装饰者模式

wmui / 3252人阅读

摘要:当接口比较多,装饰器也比较多时,可以独立抽取一个装饰器父类,实现目标类的所有接口,再创建真正的装饰器来继承这个父类。四的实现方式提供了一种类似的注解的语法糖,来实现装饰者模式。

欢迎关注我的公众号睿Talk,获取我最新的文章:

一、前言

所谓装饰者模式,就是动态的给类或对象增加职责的设计模式。它能在不改变类或对象自身的基础上,在程序的运行期间动态的添加职责。这种设计模式非常符合敏捷开发的设计思想:先提炼出产品的MVP(Minimum Viable Product,最小可用产品),再通过快速迭代的方式添加功能。

二、传统面向对象语言的实现方式
var Car = function() {}
Car.prototype.drive = function() {
    console.log("乞丐版");
}

var AutopilotDecorator = function(car) {
    this.car = car;
}
AutopilotDecorator.prototype.drive = function() {
    this.car.drive();
    console.log("启动自动驾驶模式");
}

var car = new Car();
car = new AutopilotDecorator(car);
car.drive();    //乞丐版;启动自动驾驶模式;

这种方式的实现要点是装饰器类要维护目标对象的一个引用,同时要实现目标类的所有接口(这个例子里的drive方法,如果还有其它方法,比如brake,AutopilotDecorator也要实现)。调用方法时,先执行目标对象原有的方法,再执行自行添加的特性。

当接口比较多,装饰器也比较多时,可以独立抽取一个装饰器父类,实现目标类的所有接口,再创建真正的装饰器来继承这个父类。

var Car = function() {}
Car.prototype.drive = function() {
    console.log("乞丐版");
}
/* 多了一个刹车方法 */
Car.prototype.brake = function() {
    console.log("刹车");
}

/* 实现所有接口的装饰器父类 */
var CarDecorator = function(car) {
    this.car = car;
}
CarDecorator.prototype = {
    drive: function() {
        this.car.drive();
    },
    brake: function() {
        this.car.brake();
    }
}

/* 真正的装饰器 */
var AutopilotDecorator = function(car) {
    CarDecorator.call(this, car);
}
AutopilotDecorator.prototype = new CarDecorator();
AutopilotDecorator.prototype.drive = function() {
    this.car.drive();
    console.log("启动自动驾驶模式");
}

/* 真正的装饰器 */
var HybridDecorator = function(car) {
    CarDecorator.call(this, car);
}
HybridDecorator.prototype = new CarDecorator();
HybridDecorator.prototype.brake = function() {
    this.car.brake();
    console.log("启动充电模式");
}

var car = new Car();
car = new AutopilotDecorator(car);
car = new HybridDecorator(car);
car.drive();    //乞丐版;启动自动驾驶模式;
car.brake();    //刹车;启动充电模式;
三、JS基于对象的实现方式
var car = {
    drive: function() {
        console.log("乞丐版");
    }
}

var driveBasic = car.drive;

var autopilotDecorator = function() {
    console.log("启动自动驾驶模式");
}

var carToDecorate = Object.create(car);

carToDecorate.drive = function() {
    driveBasic();
    autopilotDecorator();
}

carToDecorate.drive();    //乞丐版;启动自动驾驶模式;

这种实现方式完全是基于JS自身的语言特点做考量。定义类的目的是实现代码的封装和复用,而JS这门语言是没有类的概念的。它只有2种数据类型:基本类型和对象类型。实现逻辑的封装和代码的重用只需要通过对象来组织代码,然后利用原生提供的克隆机制(Object.create)来达到目的。

从代码的角度看,如果想扩展drive方法,只需要用一个变量来保存原函数的引用,然后再重写drive方法就可以了。在重写的方法里面,只要记得调用方法原有的行为就行。

另外,我们可以通过以下的工具函数,达到装饰函数的目的:

Function.prototype.after = function(afterfn) {
    var _self = this;
    return function() {
        var ret = _self.apply(this, arguments);
        afterfn.apply(this, arguments);
        return ret;
    }
}

var car = {
    drive: function() {
        console.log("乞丐版");
    }
}

var autopilotDecorator = function() {
    console.log("启动自动驾驶模式");
}

var carToDecorate = Object.create(car);

carToDecorate.drive = car.drive.after(autopilotDecorator);

carToDecorate.drive();    //乞丐版;启动自动驾驶模式;

通过在Function的原型链上定义after函数,给所有的函数都赋予了被扩展的功能,当然也可以根据需要定义一个before的函数,在函数执行前去做一些操作。这种实现方式借鉴了AOP(Aspect Oriented Programming,面向切面编程)的思想。

四、ES7的实现方式

ES7提供了一种类似的Java注解的语法糖decorator,来实现装饰者模式。使用起来非常简洁:

function autopilotDecorator(target, key, descriptor) {
    const method = descriptor.value;
    
    descriptor.value = () => {
        method.apply(target);
        console.log("启动自动驾驶模式");
    }
    
    return descriptor;
}

class Car {
    @autopilotDecorator
    drive() {
        console.log("乞丐版");
    }
}

let car = new Car();
car.drive();    //乞丐版;启动自动驾驶模式;

decorator的实现依赖于ES5的Object.defineProperty方法。defineProperty所做的事情是为一个对象增加新的属性,或者更改某个已存在的属性。调用方式是Object.defineProperty(obj, prop, descriptor)

var o = {}; // 创建一个新对象

// 在对象中添加一个属性
Object.defineProperty(o, "name", {
  value : "Dickens",
  writable : true,
  enumerable : true,
  configurable : true
});

// 在对象中添加一个方法
Object.defineProperty(o, "sayHello", {
  value : function() {
        console.log("Hello, my name is: ", this.name)
  },
  writable : true,
  enumerable : true,
  configurable : true
});

o.sayHello()    //Hello, my name is:  Dickens

decorator的参数跟defineProperty是完全一样的,含义也类似,通过修改descripter,就能达到扩展功能的目的。

五、总结

本文介绍了装饰者模式的基本概念,并通过不同的实现方式来介绍使用方法。对于不同的使用方法,也作了比较透彻的解释,让大家不但知其然,还知其所以然。

装饰者模式是一种十分常用且功能强大的模式,利用ES7的语法糖,我们能用非常简洁的方式来表达装饰的意图,推荐大家在实际项目中用起来。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/93344.html

相关文章

  • TS下的装饰模式(Decorator)

    摘要:装饰者模式装饰者模式就是动态的给类或对象增加功能的设计模式。下的实现里的装饰器目前处在建议征集的第二阶段,不被浏览器所支持,如果想要提前使用这个新特性就需要,等工具进行转译。这里介绍下的用法。 1.1、装饰者模式 装饰者模式就是动态的给类或对象增加功能的设计模式。在程序运行时动态的给一个具备基础功能的类或对象添加新的功能,并且不会改变会破坏基础类和对象的功能。先提炼出产品的最小可用产品...

    SolomonXie 评论0 收藏0
  • javascript设计模式 --- 装饰模式

    摘要:设计模式装饰者模式何为装饰者,意思就是,在不影响对象主功能的情况下,再添加一些额外的功能,使对象具备更多的功能。与继承相比,装饰者是一种更灵活轻便的做法。 javascript设计模式 --- 装饰者模式 何为装饰者,意思就是,在不影响对象主功能的情况下,再添加一些额外的功能,使对象具备更多的功能。与继承相比,装饰者是一种更灵活轻便的做法。下面我们看看javascript里装饰者模式 ...

    kumfo 评论0 收藏0
  • 学学AOP之装饰模式

    摘要:但是,这样做的后果就是,我们会不断的改变本体,就像把凤姐送去做整形手术一样。在中,我们叫做引用装饰。所以,这里引入的装饰模式装饰亲切,熟悉,完美。实例讲解装饰上面那个例子,只能算是装饰模式的一个不起眼的角落。 装饰者,英文名叫decorator. 所谓的装饰,从字面可以很容易的理解出,就是给 土肥圆,化个妆,华丽的转身为白富美,但本体还是土肥圆。 说人话.咳咳~ 在js里面一切都是对...

    nihao 评论0 收藏0
  • 装饰模式能做什么?

    摘要:自行车的基类如下其它方法那么我们可以先创建一个装饰者模式基类这个基类其实没有做什么事情,它只是接受一个实例,实现其对应的方法,并且将调用其方法返回而已。 showImg(https://segmentfault.com/img/bVbs3pt?w=650&h=651); 什么是装饰者模式 装饰者模式是一种为函数或类增添特性的技术,它可以让我们在不修改原来对象的基础上,为其增添新的能力和...

    Ilikewhite 评论0 收藏0
  • ES7-Decorator-装饰模式

    摘要:装饰者要实现这些相同的方法继承自装饰器对象创建具体的装饰器,也是接收作对参数接下来我们要为每一个功能创建一个装饰者对象,重写父级方法,添加我们想要的功能。 装饰模式 仅仅包装现有的模块,使之 更加华丽 ,并不会影响原有接口的功能 —— 好比你给手机添加一个外壳罢了,并不影响手机原有的通话、充电等功能; 使用 ES7 的 decorator ES7 中增加了一个 decorator 属性...

    zhangxiangliang 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<