1

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

  1. mixin 可能会覆盖现有的方法
  2. mixin 可能会提供新的方法
  3. 给定的 mixin 方法应该能够引用 super 从而允许跨多个 mixin 的同名行为通过管道传输到一起
  4. 从对象中删除 mixin 应该不会比添加 mixin 更难
  5. 我想将 mixins 推入对象中。也就是说,我希望不要包装/装饰对象,因为它已经过时了对原始对象的引用。

在 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 将提供一个允许这样做的代理,但我想知道我是否可能错过了一个更简单的方法。

什么样的设计模式或机制可以让添加插件行为变得容易,以后也同样容易删除?是否有任何框架在这些方面做一些事情?

4

1 回答 1

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'

我发现如果你小心为什么创建 mixin,它实际上工作得很好。我从不需要删除 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'

因此,您需要做的就是将该功能包装成更通用的东西。

于 2013-05-03T18:07:59.037 回答