JavaScript:将行为插入对象并轻松删除这些行为

时间:2013-05-03 17:58:20

标签: javascript design-patterns rack

在JavaScript中,我想在长时间运行的应用程序中实例化一个对象。该对象应该允许自己使用mixins进行扩充。有一些设计限制:

  1. mixin可以覆盖现有方法
  2. mixin可能会提供新方法
  3. 给定的mixin方法应该能够引用super,从而允许跨越几个mixin的同名行为被管道连接
  4. 从对象中移除mixin并不比添加mixin更困难
  5. 我想将mixins推入对象。也就是说,我希望不要包装/装饰对象,因为outdates持有对原始对象的引用。
  6. 在JS中,通常mixins将他们的方法直接复制到一个对象上。如果您不想轻易拔掉新行为,这很好。我们的想法是,这些行为应该很容易随时添加或删除,因为应用程序可以无限期地运行,并且使用对象来添加行为并不会使以后删除它变得简单。

    我指的是'mixins'。主要思想是对象可以插入或拔出可以通过管道连接的行为;机制本身并不那么重要。有些熟悉Rack的人知道这有多大用处。

    var tim = new Person('Tim'); //at 12:00pm
    tim.eat()                    //at 12:00pm -- native Person behavior
    tim.addBehavior(husband)     //at 12:00pm
    tim.kissWife()               //at 12:00pm -- husband behavior
    tim.addBehavior(father)      //at 12:00pm
    tim.addBehavior(hungry)      //at 12:00pm -- augments the native eat behavior
    tim.addBehavior(bowler)      //at 5:00pm
    tim.bowl()                   //at 5:00pm
    tim.performDailyDuties()     //at 5:00pm -- includes husband and father duties
    tim.removeBehavior(bowler)   //at 5:00pm -- easily remove behavior
    tim.bowl()                   //at 5:01pm -- error!
    tim.kissWife()               //at 5:01pm
    

    我不想......

    var husbandTim = new Husband(tim)
    var bowlerTim  = new Bowler(husbandTim)
    

    ...因为它很难删除一个特定的行为。另外,所有引用tim的地方怎么样?那些地方不会意识到新的行为。

    不幸的是,JS并没有提供任何让我知道的东西。 ES6将提供一个允许这样做的代理,但我想知道我是否可能错过了一个更简单的方法。

    哪些设计模式或机制可以轻松添加以后易于删除的插件行为?任何框架都可以按照这些方式做点什么吗?

1 个答案:

答案 0 :(得分:0)

我之前创建了一个名为Uberproto的ES5继承库,它允许您将mixins添加到对象并调用覆盖的方法。例如:

var PersonObject = {
    init : function(name) {
        this.name = name;
    },

    fullName : function() {
        return this.name;
    }
};

Proto.mixin({
    fullName : function() {
        return 'My name is: ' + this._super();
    }
}, PersonObject);

// Create a plain object without calling the constructor
var instance = Object.create(PersonObject);
instance.name = 'Dude';
console.log(instance.fullName()); // 'My name is: Dude'

我发现如果你小心为什么创建mixins,它确实很有效。我从来不需要删除mixin,但它应该像添加原始方法之前存储引用一样简单:

var PersonObject = {
    init : function(name) {
        this.name = name;
    },

    fullName : function() {
        return this.name;
    }
};

var backup = {
    fullName: PersonObject.fullName
};

Proto.mixin({
    fullName : function() {
        return 'My name is: ' + this._super();
    }
}, PersonObject);

// Create a plain object without calling the constructor
var instance = Object.create(PersonObject);
instance.name = 'Dude';
console.log(instance.fullName()); // 'My name is: Dude'

// Restore old mixin
PersonObject.fullName = backup.fullName;
var instance = Object.create(PersonObject);
instance.name = 'Dave';
console.log(instance.fullName()); // 'Dave'

所以你需要做的就是将这个功能包装成更通用的东西。