使用RequireJS在单例和原型范围之间切换

时间:2014-02-26 13:37:20

标签: javascript dojo singleton requirejs

Spring有非常有用的选项,我定义一个bean,我定义了一个范围。如果它是 singleton ,则只创建一个实例。通过 prototype ,每次需要bean时,都会创建一个新实例。

RequireJS默认提供单例,所以使用这样简单的模块:

Singleton.js

define([], function() {
    console.log('Instance  initialization')
    var items = []
    var singleton =  {
      getItems: function() {
        return items
      },
      setItems: function(newItems) {
        items = newItems
      },
      addItem: function(item) {
        items.push(item)
      }
    };
    return singleton;
})

和用法:

require(["showcase/modules/Singleton"], function(Singleton){
  Singleton.addItem('item1')
  console.log(Singleton.getItems())
})
require(["showcase/modules/Singleton"], function(Singleton){
  Singleton.addItem('item2')
  console.log(Singleton.getItems())
})

输出将是:

  

实例初始化   [ “ITEM1”]   [“item1”,“item2”]

是否可以以这种方式定义和使用模块,如果我想使用原型或单例范围,我可以在模块定义中切换?所以在我的情况下,如果不改变用法,我会得到:

  

实例初始化   [ “ITEM1”]   实例初始化   [ “ITEM2”]

我正在使用Dojo中的RequireJS,只是出现语法差异

1 个答案:

答案 0 :(得分:2)

好吧,首先问题是当你使用AMD加载器导入模块时,你实际上会得到一个实例,但是第二次导入同一个模块时,实际上会返回相同的实例(问题1)。

要解决此问题,您应该使用工厂设计模式来获取实例,并将单例对象转换为可以实例化的类(问题2)。您的工厂可以使用名为getInstance()的方法,该方法接受可以在单例/原型之间切换的boolean参数。

因此,在不改变您的使用情况的情况下,由于我刚刚解决的问题,您无法做到这一点。我能想出的最好的解决方案(有工厂)是:

Singleton.js

define([], function() {
    console.log('Instance  initialization');

    // Singleton class
    var Singleton = function() {
      this.items = [];
      this.getItems = function() {
        return this.items;
      };
      this.setItems = function(newItems) {
        this.items = newItems;
      };
      this.addItem = function(item) {
        this.items.push(item);
      }
    };

    // Factory
    var factory = {
      singletonInstance: new Singleton(),
      getInstance: function(/** Boolean */ isSingleton) {
        if (isSingleton === true) {
          return this.singletonInstance;
        } else {
          return new Singleton();
        }
      }
    };
    return factory;
});

用法(单身)

require(["app/Singleton"], function(singletonFactory){
  var Singleton = singletonFactory.getInstance(true);
  Singleton.addItem('item1');
  console.log(Singleton.getItems());
});
require(["app/Singleton"], function(singletonFactory){
  var Singleton = singletonFactory.getInstance(true);
  Singleton.addItem('item2');
  console.log(Singleton.getItems());
});

用法(多个实例)

require(["app/Singleton"], function(singletonFactory){
  var Singleton = singletonFactory.getInstance(false);
  Singleton.addItem('item3');
  console.log(Singleton.getItems());
});
require(["app/Singleton"], function(singletonFactory){
  var Singleton = singletonFactory.getInstance(false);
  Singleton.addItem('item4');
  console.log(Singleton.getItems());
});

如果您对完整示例感兴趣,请访问Plunker

最终,您可以将工厂包装为插件,以便您可以实际执行以下操作:

require([ "app/Object!singleton", "app/Object!prototype" ], function() {

});

但是我不知道RequireJS是否也支持这个(如果我理解的话,它应该是两个AMD加载器的通用故事)。