js设计模式 - 装饰者模式

什么是装饰者模式

装饰者模式可以动态地给一个对象添加一些额外的职责。就增加功能来说,装饰者模式比通过继承生成子类更为灵活。

下面通过一个例子来详细的介绍一下。

我们销售一台电脑,每个电脑都是一个新的Computer对象,它都有一个price属性来表示价格,并且可以通过它的getPrice方法来得到它的价格:

 

var Computer = function(price){
  this.price = price || 100;
};

Computer.prototype.getPrice = function(){
  return this.price;
};

现在有个客户想要再加个内存条,如果通过继承的方式,我们要新增一个ComputerWithMemory对象。

 

var ComputerWithMemory = function(price){
  Computer.constructor.call(this, price);
};
ComputerWithMemory.prototype = new Computer();
ComputerWithMemory.prototype.getPrice = function(){
  return this.price + 20;
};

我们来验证一下:

 

var computer = new Computer();
var computer1 = new ComputerWithMemory();

computer.getPrice();  // 100
computer1.getPrice();  // 120

 

如果客户要加个固态硬盘,我们就有要再新增一个ComputerWithSSD对象,如果客户既要内存条,又要固态硬盘,那我们就要再新增一个ComputerWithMemoryAndSSD对象。

下面我们来用装饰者模式实现:

我们在Computer中加一个_decorateList属性来保存添加到对象上的装饰者列表:

var Computer = function(price){
  this.price = price || 100;
  
  this._decoratorList = [];
};

接下来,我们在Computer对象上预先定义好需要的装饰者:

Computer.decorators = {};
Computer.decorators.memory = {
  getPrice : function(price){
    return price + 20;
  }
};

Computer.decorators用来存储我们的装饰者。上面我们定义了一个加内存条的装饰者memory,注意它的getPrice方法是带参数price的。

到这里装饰者我们已经有了,但是装饰者是需要注册到具体对象上去的,我们就需要在加一个注册的方法:

Computer.prototype.decorate = function(decorate){
  this._decoratorList.push(decorate);
};

注册方法很简单,就是把要注册的装饰者加入到对象的装饰者列表中。参数decorate表示装饰者的名字,例如如果是上面的memory装饰者,参数decorate就是字符串“memory”。

最后我们再重写一下getPrice方法:

Computer.prototype.getPrice = function(){
  // 先得到我们的原价  
  var price = this.price;
  // 遍历注册了的装饰者
  for(var i = 0, len = this._decoratorList.length; i < len; i++){
    var name = this._decoratorList[i];
    // 根据装饰者的名字得到装饰者
    // 再调用装饰者的getPrice方法来处理我们的价格price
    price = Computer.decorators[name].getPrice(price);
  }
  
  return price;
};

这样我们的装饰者模式就完成了,我们再来测试一下:

var computer = new Computer();
computer.getPrice();    // 100

// 加个内存条
computer.decorate('memory');
computer.getPrice();    // 120

现在如果我们要想加一个固态硬盘,我们只要在Computer对象上再加个ssd装饰者:

Computer.decorators.ssd = {
  getPrice : function(price){
    return price + 30;
  }
};

再来测试一下:

var computer = new Computer();

// 加个固态硬盘
computer.decorate('ssd');
computer.getPrice();    // 130

// 再加个内存条
computer.decorate('memory');
computer.getPrice();    // 150

 

posted @ 2015-12-03 17:11  Lbin89  阅读(203)  评论(0编辑  收藏  举报