一、装饰者模式
在装饰者模式中,可以在运行时动态添加附加功能到对象中,当处理静态类时,这可能是一个挑战。在javascript中,由于对象是可变的,因此,添加功能到对象中的过程本身并不是问题。
实现一:利用继承,来增强对象的功能
//装饰者模式 1
function Sale(price){
this.price = price || 100;
}
Sale.prototype.getPrice = function(){
return this.price;
}
Sale.prototype.decorate = function(decorator){
//临时构造函数,继承当前对象,装饰新对象
var F = function(){},
overrides = this.constructor.decorators[decorator],
i,newobj;
F.prototype = this;
newobj = new F();
//父类引用相当于__proto__
newobj.father = F.prototype;
for(i in overrides){
if(overrides.hasOwnProperty(i)){
newobj[i] = overrides[i];
}
}
return newobj;
}
Sale.decorators = {};
Sale.decorators.fedtax = {
getPrice:function(){
var price = this.father.getPrice();
price += price * 5 / 100;
return price;
}
};
Sale.decorators.quebec = {
getPrice:function(){
var price = this.father.getPrice();
price += price * 7.5 / 100;
return price;
}
}
Sale.decorators.money = {
getPrice:function(){
return "$" + this.father.getPrice().toFixed(2);
}
}
Sale.decorators.cdn = {
getPrice:function(){
return "CDN$" + this.father.getPrice().toFixed(2);
}
}
//测试
var sale = new Sale(100);
sale = sale.decorate('fedtax');
sale = sale.decorate('quebec');
sale = sale.decorate('money');
console.log(sale.getPrice()); //结果 $112.88
sale = new Sale(100);
sale = sale.decorate('fedtax');
sale = sale.decorate('cdn');
console.log(sale.getPrice()); //结果 CDN$ 105.00
1.装饰器都是静态对象,里面包含了要重载的方法。
2.调用子对象的方法,会先调用父对象的方法
实现二、使用装饰名称数组,不涉及继承
//装饰模式2
function Sale(price){
this.price = price || 100;
this.decorators_list = [];
}
Sale.prototype.decorate = function(decorator){
this.decorators_list.push(decorator);
}
Sale.prototype.getPrice = function(){
var price = this.price,
i,
max = this.decorators_list.length,
name;
for(i = 0;i<max;i++){
name = this.decorators_list[i];
price = Sale.decorators[name].getPrice(price);
}
return price;
}
Sale.decorators = {};
Sale.decorators.fedtax = {
getPrice:function(price){
price += price * 5 / 100;
return price;
}
};
Sale.decorators.quebec = {
getPrice:function(price){
price += price * 7.5 / 100;
return price;
}
}
Sale.decorators.money = {
getPrice:function(price){
return "$" + price.toFixed(2);
}
}
Sale.decorators.cdn = {
getPrice:function(price){
return "CDN$" + price.toFixed(2);
}
}
//测试
var sale = new Sale(100);
sale.decorate('fedtax');
sale.decorate('quebec');
sale.decorate('money');
console.log(sale.getPrice()); //结果 $112.88
sale = new Sale(100);
sale.decorate('fedtax');
sale.decorate('cdn');
console.log(sale.getPrice()); //结果 CDN$ 105.00
此种方法利用了javascript本身的动态性,不需要用继承。简单的将前面的方法结果作为参数传递到下一个方法,而不是调用链中前面的方法。
这种实现方法可以很容易的支持反装饰或者撤销装饰,只需要简单的从装饰列表中删除项目即可。
缺点:该实现只有一个被装饰的方法,如果要装饰多个方法。修改列表数据结构为对象。