欢迎关注个人公众号睿Talk
,获取我最新的文章:javascript
所谓装饰者模式,就是动态的给类或对象增长职责的设计模式。它能在不改变类或对象自身的基础上,在程序的运行期间动态的添加职责。这种设计模式很是符合敏捷开发的设计思想:先提炼出产品的MVP(Minimum Viable Product,最小可用产品)
,再经过快速迭代的方式添加功能。java
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也要实现)。调用方法时,先执行目标对象原有的方法,再执行自行添加的特性。编程
当接口比较多,装饰器也比较多时,能够独立抽取一个装饰器父类,实现目标类的全部接口,再建立真正的装饰器来继承这个父类。segmentfault
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(); //刹车;启动充电模式;
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
方法就能够了。在重写的方法里面,只要记得调用方法原有的行为就行。 app
另外,咱们能够经过如下的工具函数,达到装饰函数的目的:函数
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提供了一种相似的Java注解的语法糖decorator
,来实现装饰者模式。使用起来很是简洁:this
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)
。spa
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的语法糖,咱们能用很是简洁的方式来表达装饰的意图,推荐你们在实际项目中用起来。