模式动机
给一个类或者对象增加行为有两种方式:
继承机制:使用继承是给现有类添加行为的一种有效方法, 通过继承子类在拥有自身方法的同时还拥有父类的方法.
关联机制: 把一个类的对象嵌入到另外一个对象里面, 由另外一个对象来决定是否调用嵌入对象的行为以便来扩展自己的行为. 这个嵌入的对象我们称为装饰器.
与继承机制相比, 关联机制的主要优势在于不会破坏类的封装性. 继承本身就是耦合度比较高的一种静态关系, 而关联关系拥有更好的松耦合关系, 有利于后期代码的维护.
装饰者模式在不需要创建更多子类情况下就可以把功能进行扩展。
模式定义
装饰者模式(Decorator Pattern): 动态的给一个对象添加额外的职责. 装饰者模式可以在不改变对象自身基础之上, 在程序运行之间给对象动态的添加职责.
代码论证
以飞机大战为例, 随着飞机等级提升, 飞机能力也提升, 从开始的发射普通子弹到可以发射导弹, 原子弹.
分别用两种机制实现一下,对比下代码的方式:
// 继承机制
class Plane {
fire () {
console.log('发射普通子弹')
}
}
class MissilePlane extends Plane {
fire () {
super.fire();
console.log('发射导弹')
}
}
class AtomPlane extends Plane {
fire () {
super.fire();
console.log('发射原子弹')
}
}
const p = new Plane();
const missile = new MissilePlane();
const atom = new AtomPlane();
p.fire(); // 发射普通子弹
missile.fire(); // 发射普通子弹 发射导弹
atom.fire(); // 发射普通子弹 发射原子弹
装饰者模式:
class Plane {
fire () {
console.log('发射普通子弹')
}
}
// 创建两个装饰类
class MissileDecorator {
constructor (plane) {
this.plane = plane;
}
fire () {
this.plane.fire();
console.log('发射导弹')
}
}
class AtomDecorator {
constructor (plane) {
this.plane = plane
}
fire () {
this.plane.fire();
console.log('发射原子弹')
}
}
const p = new Plane();
const missile = new MissileDecorator(p);
const atom = new AtomDecorator(p);
p.fire(); // 发射普通子弹
missile.fire(); // 发射普通子弹 发射导弹
atom.fire(); // 发射普通子弹 发射原子弹
可以看到装饰者模式这种动态增加职责的方式, 并没有去改变对象本身(Plane), 而是把对象放入另外一个对象(装饰类)之中. 另外装饰者对象与被装饰的对象拥有一致的接口, 对使用者来说这个对象是透明的.
装饰器
许多面向对象的语言都有修饰器(Decorator)函数, 如python,用来修改类的行为。目前,有一个提案将这项功能,引入了 ECMAScript。
举一个简单的demo让大家看一看:
@testable // 就是一个修饰器。它修改了MyTestableClass这个类的行为,为它加上了静态属性isTestable
class MyTestableClass {
// ...
}
// testable函数的参数target是MyTestableClass类本身。
function testable(target) {
target.isTestable = true;
}
MyTestableClass.isTestable // true
装饰器你可以理解为在不改变某个类源代码行为的情况下, 可以很方便的给某个对象扩展属性与方法.
更多了解推荐阅读: ECMAScript 6入门
模式分析
优点:
装饰者模式与继承关系的目的都是要扩展对象的功能,但是装饰者模式可以提供比继承更多的灵活性。
可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的装饰器,从而实现不同的行为。
通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出具有很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象
具体装饰类可以根据需要进行扩展,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”
缺点:
对于多次装饰的对象,调试时寻找错误需要逐级排查,比较繁琐.
装饰者模式比继承关系要创建更多的对象(装饰类), 增加系统的复杂读.
适用环境
在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。
当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。不能采用继承的情况主要有两类:第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;第二类是因为类定义不能继承(JS存在该情况).
如需转载,请注明文章出处和来源网址:http://www.divcss5.com/html/h63332.shtml