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

标签 javascript design-patterns rack

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

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

在 JS 中,通常 mixin 将它们的方法直接复制到对象上。如果您不想轻易取消新行为,这很好。我们的想法是,这些行为应该易于随时添加或删除,因为应用程序可能无限期地运行,并且使用对象来添加行为并不会让以后删除它变得整洁和容易。

我指的是“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 将提供一个代理来实现这一点,但我想知道我是否可能错过了一个更简单的方法。

哪些设计模式或机制可以使添加插件行为变得容易,并且以后也可以轻松删除?是否有框架按照这些思路做一些事情?

最佳答案

我不久前创建了一个 ES5 继承库,名为 Uberproto这确实允许您向对象添加 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'

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

关于JavaScript:将行为插入对象并轻松删除这些行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16364969/

相关文章:

java - 如何创建注入(inject)特定@Repository的通用@Service?

java - 设计音频架构

java - 如何进行不同类型的对象状态验证

ruby - 如何将 Rack 中间件注入(inject)现有的 Rack 应用程序?

javascript - Angular.forEach 只返回一个结果?

javascript - onclick事件不改变元素ID

javascript - 删除 Swiper 中的字幕

javascript - 如何使用 JSON 数据创建动态表?

ruby - 在 Sinatra 中跟踪 "conversation"流

ruby-on-rails - 带有 Devise 的 JSON Web token