装饰者模式(Decorator Pattern):在不改变原类和继承的情况下动态扩展对象功能,通过包装一个对象来实现一个新的具有原对象相同接口的新的对象。
装饰者模式的特点:
1. 在不改变原对象的原本结构的情况下进行功能添加。
2. 装饰对象和原对象具有相同的接口,可以使客户以与原对象相同的方式使用装饰对象。
3. 装饰对象中包含原对象的引用,即装饰对象是真正的原对象经过包装后的对象。
二、Javascript装饰者模式详解:
描述:
装饰者模式中,可以在运行时动态添加附加功能到对象中。当处理静态类时,这可能是一个挑战。在Javascript中,由于对象是可变的,因此,添加功能到对象中的过程本身并不是问题。
装饰者模式的一个比较方便的特征在于其预期行为的可定制和可配置特性。可以从仅具有一些基本功能的普通对象开始,然后从可用装饰资源池中选择需要用于增强普通对象的哪些功能,并且按照顺序进行装饰,尤其是当装饰顺序很重要的时候。
实现装饰者模式的其中一个方法是使得每个装饰者成为一个对象,并且该对象包含了应该被重载的方法。每个装饰者实际上继承了目前已经被前一个装饰者进行增强后的对象。每个装饰方法在“继承的对象”上调用了同样的方法并获取其值,此外它还继续执行了一些操作。
先上实例1:
//需要装饰的类(函数) function Macbook() { this.cost = function () { return 1000; }; } //计算商品的包装费 function PackagingFee(macbook) { this.cost = function () { return macbook.cost() + 75; }; } //计算商品的运费 function Freight(macbook) { this.cost = function () { return macbook.cost() + 300; }; } //计算商品的保险费用 function Insurance(macbook) { this.cost = function () { return macbook.cost() + 250; }; } // 用法 var myMacbook = new Insurance(new Freight(new PackagingFee(new Macbook()))); console.log(myMacbook.cost());//1625
我们简单的分析下上面的代码,上面的代码中,一共定义了四个函数(其中一个需要修饰的函数,三个用于修饰的函数)。
然后,声明一个变量myMacbook指向new出来的Insurance对象,Insurance对象的形参指向new出来的Freight对象,Freight对象的形参指向new出来的PackagingFee对象,PackagingFee对象的形参指向new出来的Macbook对象。
接下来,调用myMacbook的cost方法。从上面的分析,我们可以得出 myMacbook.cost()的值等于(Freight对象的cost方法+250),Freight对象的cost方法等于(PackagingFee对象的cost方法+300),PackagingFee对象的cost方法等于(Macbook对象的cost方法+75)。
所以最终的结果是:myMacbook.cost()的值 = 250 + (300 + (75 + 1000)) = 1625。
// 用法 var myMacbook = new Insurance(new Freight(new PackagingFee(new Macbook()))); console.log(myMacbook.cost());//1625 //上面的代码等价于下面拆分后的代码,或许拆分后代码你更能看出前后的逻辑性 var macbook = new Macbook(); var package = new PackagingFee(macbook); var freight = new Freight(package); var myMacbook = new Insurance(freight); //当然,如果你不想声明这么多变量(macbook、package、freight),只用一个变量也是可以的 var macbook = new Macbook(); macbook = new PackagingFee(macbook); macbook = new Freight(macbook); var myMacbook = new Insurance(macbook);
再看看实例2:
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);// add performTask method decorated.preTask = function () { console.log('pre-calling..'); }; decorated.postTask = function () { console.log('post-calling..'); }; } var concrete = new ConcreteClass(); var decorator1 = new ConcreteDecoratorClass(concrete); decorator1.performTask(); //pre-calling.. //doing something //post-calling..
实例2实际上和实例1是非常类似的,我们来简单分析下吧。首先,实例2中定义了三个函数,然后声明了两个变量concrete和decorator1,最后调用了decorator1的performTask方法。
粗看一眼,ConcreteDecoratorClass里面好像并没有performTask方法。我们先来分析下面的两行代码:
var concrete = new ConcreteClass(); //声明一个变量concrete指向new出来的ConcreteClass对象 var decorator1 = new ConcreteDecoratorClass(concrete); //声明一个变量decorator1指向new出来的ConcreteDecoratorClass对象,并传入变量concrete作为形参
然后,我们再来逐行分析下ConcreteDecoratorClass函数里面的代码: