javascript设计模式-装饰者

装饰者

基本实现

是一种为对象增加我的技术,它并不使用创建新子类手段,一切都在动态完成。这个过程相对于使用者来说是透明的。透明地把对象包装在具有同样接口的另一个对象之中。

比如可以动态的为自行车对象添加可选的特色配件上。比如添加4个选件,可以新定义4个超类,但如果自行车种类过多,则需要派生出N多子类。基本是不可以维护。如果用装饰者,只需要维护4个类即可,一个选件一个类。通过装饰加在各个原有的自行车上。

缺点在于,在遇到用装饰者包装起来的对象时,那些依赖于类型检查的代码会出问题,所以在设计此模式的类时不要使用类型检查。另外一点这种模式常常要引入许多小对象,它们看起来差不多,实际功能却大相径庭。所以使用此模式时要仔细,因为它的代码和API都不容易设计和使用。它的架构如下:

/* The Bicycle interface. */
var Bicycle = new Interface('Bicycle', ['assemble', 'wash', 'getPrice']);

/* 自行车实例. */
var AcmeComfortCruiser = function() { };// implements Bicycle
AcmeComfortCruiser.prototype = {
  assemble: function() {
  },
  wash: function() {
  },
  getPrice: function() {
    return 399.00;
  }
};
/* 选件类,其实就是装饰者类,所有自行车和装饰者都需要实现Bicycle接口.装饰者模式颇多得益于接口的使用,其最重要的特点之一就是它可以用来替代组件,原来使用AcmeComfortCruiser的地方都可以用装饰类来代替而不用修改源代码,下面的装饰类对原类的两个方法进行了装饰。 * 下面的superclass是个自定义的属性,是在extends方法中加上的*/
var HeadlightDecorator = function(bicycle) { // implements Bicycle
    HeadlightDecorator.superclass.constructor.call(this, bicycle);
}
extend(HeadlightDecorator, BicycleDecorator); // Extend the superclass.
HeadlightDecorator.prototype.assemble = function() {
  return this.bicycle.assemble() + ' Attach headlight to handlebars.';
};
HeadlightDecorator.prototype.getPrice = function() {
  return this.bicycle.getPrice() + 15.00;
};
var myBicycle= newAcmeComfortCruiser();//裸自行车
var myBicycle = new TaillightDecorator(myBicycle); //加了一个篮子
myBicycle = new TaillightDecorator(myBicycle); //又加了另一个篮子
alert(myBicycle.getPrice());  //得到最终的价格

简单的组合模式和装饰者模式基本一样,但有些本质的区别,组合对象并不修改方法调用,其着眼于组织对象。而装饰者存在的唯一目的就是修改方法调用而不是组织子对象,因为子对象只有一个。

装饰者的作用在于以某种方式对其组件对象的行为进行修改。这种修改可以体现在方法之前、之后添加行为或是直接替换方法,甚至添加新的方法。

上例中一次只能添加一个选件,如果多个选件,需要多次调用即可。

HeadlightDecorator.prototype.getPrice = function() {
  return this.bicycle.getPrice() + 15.00;//之后};
var FrameColorDecorator = function(bicycle, frameColor) { //implements Bicycle
  this.superclass.constructor(bicycle); // Call the superclass's constructor.
  this.frameColor = frameColor;
}
extend(FrameColorDecorator, BicycleDecorator); // Extend the superclass.FrameColorDecorator.prototype.assemble = function() {
  return 'Paint the frame ' + this.frameColor + ' and allow it to dry. ' + 
      this.bicycle.assemble();//之前,注意这个参数的传递};
LifetimeWarrantyDecorator.prototype.repair = function() {
  return 'This bicycle is covered by a lifetime warranty. Please take it to ' +'an authorized Acme Repair Center.';
};//直接替换掉原来的方法实现

添加新方法时需要注意,因为接口中并没有声明,又不适合直接改接口,这样很多装饰子类中可能会有很多无用的代码,最好的方法是使用一种称为pass-through method的技术,暂时没搞清楚其运行机制。

OUTERLOOP:对组件对象进行检查 ,并为其拥有的每一个方法创建一个通道方法。这样在装饰类外再套上另一个装饰者的话,内层装饰者定义的新方法仍然可以访问。这样不用担心新创建的方法无法访问了。

var Bicycle = new Interface('Bicycle', ['assemble', 'wash', 'getPrice']);
/* 自行车实例. */
var AcmeComfortCruiser = function() { };// implements Bicycle
AcmeComfortCruiser.prototype = {
    assemble: function() {
    },
    wash: function() {
    },
    getPrice: function() {
        return 399.00;
    }
};
var BicycleDecorator = function(bicycle) { // implements Bicycle
    this.bicycle = bicycle;
    this.interface = Bicycle;
    //这处会自动循环,通过另一种方式代替方法的调用,见最后    outerloop: for(var key in this.bicycle) {
        // Ensure that the property is a function.
        if(typeof this.bicycle[key] !== 'function') {
            continue outerloop;
        }
        for(var i = 0, len = this.interface.methods.length; i < len; i++) {
            if(key === this.interface.methods[i]) {
                continue outerloop;
            }
        }
        // Add the new method.
        var that = this;
        (function(methodName) {
            that[methodName] = function() {
                return that.bicycle[methodName]();
            };
        })(key);
    }
}
BicycleDecorator.prototype = {
    assemble: function() {
        return this.bicycle.assemble();
    },
    wash: function() {
        return this.bicycle.wash();
    },
    getPrice: function() {
        console.log('4');
        return this.bicycle.getPrice();
    }
};
var HeadlightDecorator = function(bicycle) { // implements Bicycle
    HeadlightDecorator.superclass.constructor.call(this, bicycle);
}
extend(HeadlightDecorator, BicycleDecorator); // Extend the superclass.
HeadlightDecorator.prototype.assemble = function() {
    return this.bicycle.assemble() + ' Attach headlight to handlebars.';
};
HeadlightDecorator.prototype.getPrice = function() {
    console.log('3');
    return this.bicycle.getPrice() + 15.00;
};
var TaillightDecorator = function(bicycle) { // implements Bicycle
    TaillightDecorator.superclass.constructor.call(this, bicycle);
}
extend(TaillightDecorator, BicycleDecorator); // Extend the superclass.
TaillightDecorator.prototype.assemble = function() {
    return this.bicycle.assemble() + ' Attach taillight to the seat post.';
};
TaillightDecorator.prototype.getPrice = function() {
    console.log('2');
    return this.bicycle.getPrice() + 9.00;
};
TaillightDecorator.prototype.ringBell = function() {
    console.log('1');
    return 'Bell rung.';
};
var c = new AcmeComfortCruiser();
c = new TaillightDecorator(c);
c = new HeadlightDecorator(c);
console.log(c.ringBell());//无论什么顺序都会调用console.log(c.getPrice());//423

有些时候装饰者的应用顺序很重要,但在理想情况下,装饰者应该能以一种完全与顺序无关的方式创建。如果必须要以某种顺序调用,可以结合工厂一般可以办到。某些装饰者修改组件方法的方式决定了它们需要最先或最后被应用,在此情况下工厂的作用就尤为重要。

函数装饰者

也可以用装饰者来装饰函数,通过把函数当作参数传递。在PYTHON语言中这是一个核心应用。它对函数的输出应用某种格式或执行某种转换方面非常有用。

你可能感兴趣的:(#,JavaScript设计模式,javascript,设计模式,开发语言,前端,ecmascript)