Skip to content

Instantly share code, notes, and snippets.

@kampfer
Last active December 14, 2015 02:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kampfer/5012413 to your computer and use it in GitHub Desktop.
Save kampfer/5012413 to your computer and use it in GitHub Desktop.
Decorator Pattern In JavaScript
/**
* 装饰器模式在javascript中的实现方式
*
* 装饰器模式的优点:
* 1.动态的添加和删除职责
* 2.避免子类爆炸
* 3.避免在高层次结构的类中定义过多的特性
*
* 使用多个装饰器组合生成一个多功能的对象时,创建代码会相当长,
* 可以使用工厂模式处理这个问题.
*
* 装饰器和被它装饰的类必须保持接口一致.在设计新系统时使用装饰器模式,
* 可以为装饰器和被装饰的类定义共同的父类来保证两者接口一致;
* 在重构已有系统时可以省略这个父类,直接定义一个和被装饰类接口一样的装饰器.
* 这个父类是不必需的.
*
* 当被装饰的对象的类太庞大时,就要慎重的使用装饰器.因为装饰器必须和被装饰得对象
* 保持接口一致,为了装饰一个庞大的类我们也要实现一个庞大的装饰器,有点得不偿失.
*/
function decorate(Component, decorator) {
var Class = function(comp) {
for(var prop in decorator) {
this[prop] = decorator[prop];
}
this.__component__ = comp;
};
//Class继承Compoent的所有方法
var F = function() {};
F.prototype = Component.prototype;
Class.prototype = new F();
return Class;
}
function Sale(price) {
this.price = price || 100;
}
Sale.prototype.getPrice = function() {
return this.price;
};
Sale.prototype.discount = function() {
return parseInt(this.getPrice(), 10) * 0.5;
};
var FedtaxSale = decorate(Sale, {
getPrice : function() {
var price = this.__component__.getPrice();
price += price * 5 / 100;
return price;
}
});
var UsdSale = decorate(Sale, {
getPrice : function() {
return "$" + this.__component__.getPrice().toFixed(2);
}
});
var sale = new Sale(5);
var fedtaxSale = new FedtaxSale(sale);
var usdFedtaxSale = new UsdSale(fedtaxSale);
console.log( sale.getPrice() );
//console.log( sale.discount() );
console.log( fedtaxSale.getPrice() );
//console.log( fedtaxSale.discount() );
console.log( usdFedtaxSale.getPrice() );
//console.log( usdFedtaxSale.discount() );
@kampfer
Copy link
Author

kampfer commented Mar 6, 2013

1.在不改变已有代码的前提下, 添加/改变对象功能.
2.代码复用的第二种方式.(另一种方式是继承)

@kampfer
Copy link
Author

kampfer commented Mar 6, 2013

  1. 不应该改变被装饰得对象
  2. 装饰器和被装饰对象的接口一致

@kampfer
Copy link
Author

kampfer commented Mar 6, 2013

区别于继承:

  1. 继承是静态的, 运行时无法改变, 装饰器可以.
  2. 为一个基类添加大量的功能, 会造成子类爆炸.比如:
    我们有一个基类Hero, 当Hero拥有大量特性的时候, 如:runQuickly、seeFar、canfly等。那么我们生成所有可能的特性组合就有:HeroRunQuickly、HeroSeeFar、HeroCanFly、HeroRunQuicklyAndSeeFar、HeroRunQuicklyAndCanFly、HeroSeeFarAndCanFly、HearRunQuicklyAndSeeFarAndCanFly之多,使用装饰器我们只用写3个。如果我们还要加特性,那么子类就爆炸了。

@QETHAN
Copy link

QETHAN commented Apr 19, 2013

个人感觉你的做法是偏向于组合了。

@QETHAN
Copy link

QETHAN commented Apr 19, 2013

var tree = {
    name:'tree'
};
tree.decorate = function() {
    alert('Make sure the tree wont\' fall');
};

tree.getDecorator = function(deco) {

    tree[deco].prototype = this;
    return new tree[deco];
}

tree.RedBalls = function() {

    this.decorate = function() {
        this.RedBalls.prototype.decorate();
        alert('Put on some red balls');
    }
}

tree = tree.getDecorator('RedBalls');
tree.decorate();

@QETHAN
Copy link

QETHAN commented Apr 19, 2013

this.RedBalls.prototype.decorate();这里边的this,指的是什么呢。this.RedBalls也不理解。请教了

@QETHAN
Copy link

QETHAN commented Apr 24, 2013

个人觉得是tree,但是用hasOwnProperty做测试,又不对应。很奇怪

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment