js装饰者模式

js装饰者模式:

装饰者对象都将以构造函数的属性这种方式来实现

Alt text

function Sale(price){
    this.price = price || 100;
}
Sale.prototype.getPrice = function(){
    return this.price;
};
Sale.decorators =  {
    fedtax : {
        getPrice:function(){
            var price = this.uber.getPrice();
            price += price * 5 / 100;
            return price;
        }
    },
    quebec : {
        getPrice : function(){
            var price = this.uber.getPrice();
            price += price * 7.5 / 100;
            return price;
        }
    },
    money : {
        getPrice : function(){
            return '$' + this.uber.getPrice().toFixed(2);
        }
    },
    cdn : {
        getPrice : function(){
            return 'CDN$ ' + this.uber.getPrice().toFixed(2);
        }
    }
};
Sale.prototype.decorate = function(decorator){
    var F = function(){},
        overrides = this.constructor.decorators[decorator],
        i,newobj;
    console.log(this);
    F.prototype = this;  //除了第一次,每一次this的值都上一次的一个构造函数F的实例
    newobj = new F();
    newobj.uber = F.prototype;
    for(i in overrides){
        if(overrides.hasOwnProperty(i)){
            newobj[i] = overrides[i];
        }
    }
    return newobj;
};
var sale = new Sale(100);
sale = sale.decorate('fedtax');
sale = sale.decorate('quebec');
//sale = sale.decorate('money');
sale = sale.decorate('cdn');
sale.getPrice();  //先找到cdn的getPrice方法,依次再找this.uber.getPrice(),直到Sale.prototype.getPrice的方法,再从最内到往逐个运行

下面是最后newobj的原型结构

newobj: F
getPrice: function (){
    arguments: null
    caller: null
    length: 0
    name: ""
    prototype: Sale.decorators.cdn.getPrice        //cdn
    __proto__: function Empty() {}
    <function scope>
    uber: F
    __proto__: F
    getPrice: function (){
        arguments: null
        caller: null
        length: 0
        name: ""
        prototype: Sale.decorators.quebec.getPrice     //quebec
        constructor: function (){
        __proto__: Object
        __proto__: function Empty() {}
        <function scope>
        uber: F
        __proto__: F
        getPrice: function (){
            arguments: null
            caller: null
            length: 0
            name: ""
            prototype: Sale.decorators.fedtax.getPrice      //fedtax
            __proto__: function Empty() {}
            <function scope>
            uber: Sale
            __proto__: Sale
            price: 100
            __proto__: Sale          //Sale.prototype.getPrice
            constructor: function Sale(price){
            decorate: function (decorator){
            getPrice: function (){
            __proto__: Object

还有一种使用列表来实现,这种方法更为简单,也不涉及继承,也更易于理解

Alt text

var Sale = function (price){
    this.price = (price > 0 ) || 100;  //this.price为true的时候,在运算当中会作为1来处理,如果为false的时候,在参与参与去处的过程当中会作为0来处理
    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 = {
    fedtax : {
        getPrice : function(price){
            return price + price * 5 / 100;
        }
    },
    quebec : {
        getPrice : function(price) {
            return price + price * 7.5 / 100;
        }
    },
    money :{
        getPrice : function(price){
            return '$' + price.toFixed(2);
        }
    }
};
var sale = new Sale(100);
sale.decorate('fedtax');
sale.decorate('quebec');
sale.decorate('money');
sale.getPrice();