介绍
装饰者提供比继承更有弹性的替代方案。 装饰者用用于包装同接口的对象,不仅允许你向方法添加行为,而且还可以将方法设置成原始对象调用(例如装饰者的构造函数)。
装饰者用于通过重载方法的形式添加新功能,该模式可以在被装饰者前面或者后面加上自己的行为以达到特定的目的。
正文
那么装饰者模式有什么好处呢?前面说了,装饰者是一种实现继承的替代方案。当脚本运行时,在子类中增加行为会影响原有类所有的实例,而装饰者却不然。取而代之的是它能给不同对象各自添加新行为。如下代码所示:
//需要装饰的类(函数) function Macbook() { this.cost = function () { return 1000; }; }function Memory(macbook) { this.cost = function () { return macbook.cost() + 75; }; }
function BlurayDrive(macbook) { this.cost = function () { return macbook.cost() + 300; }; }
function Insurance(macbook) { this.cost = function () { return macbook.cost() + 250; }; }
// 用法 var myMacbook = new Insurance(new BlurayDrive(new Memory(new Macbook()))); console.log(myMacbook.cost());
下面是另一个实例,当我们在装饰者对象上调用performTask时,它不仅具有一些装饰者的行为,同时也调用了下层对象的performTask函数。
function ConcreteClass() { this.performTask = function () { this.preTask(); console.log('doing something'); this.postTask(); }; }function AbstractDecorator(decorated) { this.performTask = function () { decorated.performTask(); }; }
function ConcreteDecoratorClass(decorated) { this.base = AbstractDecorator; this.base(decorated);
decorated.preTask = function () { console.log('pre-calling..'); };
decorated.postTask = function () { console.log('post-calling..'); };
}
var concrete = new ConcreteClass(); var decorator1 = new ConcreteDecoratorClass(concrete); var decorator2 = new ConcreteDecoratorClass(decorator1); decorator2.performTask();
再来一个彻底的例子:
var tree = {}; tree.decorate = function () { console.log('Make sure the tree won\'t fall'); };tree.getDecorator = function (deco) { tree[deco].prototype = this; return new tree[deco]; };
tree.RedBalls = function () { this.decorate = function () { this.RedBalls.prototype.decorate(); // 第7步:先执行原型(这时候是Angel了)的decorate方法 console.log('Put on some red balls'); // 第8步 再输出 red // 将这2步作为RedBalls的decorate方法 } };
tree.BlueBalls = function () { this.decorate = function () { this.BlueBalls.prototype.decorate(); // 第1步:先执行原型的decorate方法,也就是tree.decorate() console.log('Add blue balls'); // 第2步 再输出blue // 将这2步作为BlueBalls的decorate方法 } };
tree.Angel = function () { this.decorate = function () { this.Angel.prototype.decorate(); // 第4步:先执行原型(这时候是BlueBalls了)的decorate方法 console.log('An angel on the top'); // 第5步 再输出angel // 将这2步作为Angel的decorate方法 } };
tree = tree.getDecorator('BlueBalls'); // 第3步:将BlueBalls对象赋给tree,这时候父原型里的getDecorator依然可用 tree = tree.getDecorator('Angel'); // 第6步:将Angel对象赋给tree,这时候父原型的父原型里的getDecorator依然可用 tree = tree.getDecorator('RedBalls'); // 第9步:将RedBalls对象赋给tree
tree.decorate(); // 第10步:执行RedBalls对象的decorate方法
总结
装饰者模式是为已有功能动态地添加更多功能的一种方式,把每个要装饰的功能放在单独的函数里,然后用该函数包装所要装饰的已有函数对象,因此,当需要执行特殊行为的时候,调用代码就可以根据需要有选择地、按顺序地使用装饰功能来包装对象。优点是把类(函数)的核心职责和装饰功能区分开了。
本文向大家介绍深入理解JavaScript系列(31):设计模式之代理模式详解,包括了深入理解JavaScript系列(31):设计模式之代理模式详解的使用技巧和注意事项,需要的朋友参考一下 介绍 代理,顾名思义就是帮助别人做事,GoF对代理模式的定义如下: 代理模式(Proxy),为其他对象提供一种代理以控制对这个对象的访问。 代理模式使得代理对象控制具体对象的引用。代理几乎可以是任何对象:文件
本文向大家介绍深入理解JavaScript系列(25):设计模式之单例模式详解,包括了深入理解JavaScript系列(25):设计模式之单例模式详解的使用技巧和注意事项,需要的朋友参考一下 介绍 从本章开始,我们会逐步介绍在JavaScript里使用的各种设计模式实现,在这里我不会过多地介绍模式本身的理论,而只会关注实现。OK,正式开始。 在传统开发工程师眼里,单例就是保证一个类只有一个实例,实
本文向大家介绍深入理解JavaScript系列(33):设计模式之策略模式详解,包括了深入理解JavaScript系列(33):设计模式之策略模式详解的使用技巧和注意事项,需要的朋友参考一下 介绍 策略模式定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化不会影响到使用算法的客户。 正文 在理解策略模式之前,我们先来一个例子,一般情况下,如果我们要做数据合法性验证,很多时候都
本文向大家介绍深入理解JavaScript系列(44):设计模式之桥接模式详解,包括了深入理解JavaScript系列(44):设计模式之桥接模式详解的使用技巧和注意事项,需要的朋友参考一下 介绍 桥接模式(Bridge)将抽象部分与它的实现部分分离,使它们都可以独立地变化。 正文 桥接模式最常用在事件监控上,先看一段代码: 上述代码,有个问题就是getBeerById必须要有浏览器的上下文才能使
本文向大家介绍深入理解JavaScript系列(43):设计模式之状态模式详解,包括了深入理解JavaScript系列(43):设计模式之状态模式详解的使用技巧和注意事项,需要的朋友参考一下 介绍 状态模式(State)允许一个对象在其内部状态改变的时候改变它的行为,对象看起来似乎修改了它的类。 正文 举个例子,就比如我们平时在下载东西,通常就会有好几个状态,比如准备状态(ReadyState)、
本文向大家介绍深入理解JavaScript系列(42):设计模式之原型模式详解,包括了深入理解JavaScript系列(42):设计模式之原型模式详解的使用技巧和注意事项,需要的朋友参考一下 介绍 原型模式(prototype)是指用原型实例指向创建对象的种类,并且通过拷贝这些原型创建新的对象。 正文 对于原型模式,我们可以利用JavaScript特有的原型继承特性去创建对象的方式,也就是创建的一