装饰者模式是一种结构型设计模式,目的是为了促进代码复用。装饰者模式与Mixin很相似,可以算是一种子类化的替代方案。
装饰者模式通常是为了添加系统的现有能力,为系统中的对象添加额外的功能,同时不影响到系统底层代码(这些额外能力父类可能并不需要,只有部分子类需要)
简单实现
// 场景描述:当你购买macbook时,可以通过cost方法来获得最终的价格,// 我们通过装饰者来扩展cost方法,当增加不同配置时,扩展cost计算方法// macbook类function MacBook (screenSize) {this.cost = function (){if (screenSize == 13) {return 999} else {return 1199}}}// 装饰者1:增加内存配置,费用上升100function Memory (macbook) {var v = macbook.cost();macbook.cost = function () {return v + 100}}// 装饰者2:增加硬盘容量,费用上升250function HardDiscCapacity (macbook) {var v = macbook.cost();macbook.cost = function () {return v + 250}}// 装饰者3:延长质保期,费用上升120function Insurance (macbook) {var v = macbook.cost();macbook.cost = function () {return v + 120}}// 使用装饰者var mb = new MacBook(13)Memory(mb)HardDiscCapacity(mb)Insurance(mb)console.log(mb.cost())// 输出1469//装饰者只影响需要装饰的实例var mb2 = new MacBook(13)console.log(mb2.cost())// 仍然输出999
在上面的例子中,装饰者重写了MacBook类的cost方法。相比直接修改MacBook的cost方法,这样的写法使我们的代码更易读,也更佳健壮。
优点
对象可以被新的行为包装或装饰,从而继续使用,并且不用担心被使用的基本对象被修改,在一些场景下,我们可以减少需要大量子类才能实现的开发复杂度。
缺点
过度放开任意扩展,会导致对象复杂变得难以管理,不熟悉这个模式的开发人员也会难以理解为何如此使用。
ES7 Decorator
es7里的Decorator(@),借鉴于python,可用于对类、方法进行装饰(不可对函数进行装饰)。通过使用Decorator可以达到装饰者模式、Mixin模式等的效果,如下:
// Mixin.jsfunction mixins(...list) {return function (target) {Object.assign(target.prototype, ...list);};}// 使用mixin// 需要混入的方法const Foo = {foo() { console.log('foo') }};// 通过decorator混入@mixins(Foo)class MyClass {}let obj = new MyClass();obj.foo() // "foo"
// 使用decorator实现一个事件触发记录器,同时能够重用function logger(topic) {return function(target, name, descriptor) {const fn = descriptor.value;descriptor.value = function() {console.log('before' + topic)let value = fn.apply(this, arguments);console.log(value)console.log('after' + topic)};};}class FooComponent {@logger('HoldMessage')holdMessage() {return { my: 'data' };}@logger('KeepMessage')keepMessage() {return { my: 'data2' };}}let foo = new FooComponent();foo.holdMessage();// beforeHoldMessage// { my: 'data' }// afterHoldMessage
具体Decorator语法和使用场景,不在本篇中进行详细描述,请大家参考ES6相关的文章
