Backbone收集多态模型

时间:2013-03-20 15:06:55

标签: backbone.js polymorphism backbone-collections

我有一群动物。

App.Collections.Animals extends Backbone.Collection
  model: App.Animal
  url: '/animals/' #returns json

这些动物类:

App.Models.Animal extends Backbone.Model

App.Models.Monkey extends App.Models.Animal
  defaults:{type:'Monkey'}

App.Models.Cat extends App.Models.Animal
  defaults:{type:'Cat'}

App.Models.Dog extends App.Models.Animal
  defaults:{type:'Dog'}

当集合填充JSON(记录包含类型属性)时,我希望模型被实例化为子类模型(Monkey,Cat,Dog)而不是Animal。你怎么能做到这一点?

3 个答案:

答案 0 :(得分:12)

来自Backbone documentation

  

集合也可以通过覆盖它来包含多态模型   具有返回模型的函数的属性。

var Library = Backbone.Collection.extend({

  model: function(attrs, options) {
    if (condition) {
      return new PublicDocument(attrs, options);
    } else {
      return new PrivateDocument(attrs, options);
    }
  }

});

答案 1 :(得分:6)

解决方案很简单(请原谅JS,我不知道CoffeeScript):

var SmartZoo = Backbone.Collection.extend({
    model: function (attrs, options) {
        // This code assumes that the object looks something like '{ type: "Cat", ... }'.
        switch (attrs.type) {
            case 'Cat':
                return new Cat(attrs, options);
            case 'Dog':
                return new Dog(attrs, options);
            default: // Unknown subclass
                return new Animal(attrs, options);
        }
    }
});

你必须:

  1. 在模型中包含一个属性,您可以从中推断要创建的Backbone模型的类型。在此示例中,我的对象包含一个名为“type”的属性,其值是表示它的Backbone类型的全名。请务必将其设置为模型的默认值或初始化,以便您还可以将真实模型实例添加到集合中。
  2. 将集合的models属性定义为函数。此函数的第一个参数将是原始JS对象(如果这是您传入的内容),或者是Backbone模型的属性对象。无论哪种方式,您都可以将您的类型字段作为此对象的属性进行访问。
  3. 执行逻辑以从类型字段推断出正确的模型。
  4. 从模型函数返回正确模型的实例。
  5. 这是一个JSFiddle,它显示了这个多态集合:http://jsfiddle.net/FiddlerOnTheTarmac/uR2Sa/

答案 2 :(得分:0)

覆盖主干集合的_prepareModel。集合new在定义时使用子类,否则使用默认模型。

class App.Collections.Animals extends Backbone.Collection

 model: App.Models.Animal

 _prepareModel: (attrs, options) ->
   if attrs instanceof Backbone.Model
   attrs.collection = @
   return attrs

   options || (options = {})
   options.collection = @
   model_class = APP.Models[attrs.ntype] or this.model
   model = new model_class(attrs, options)
   if (!model._validate(attrs, options))
     false
   else
     model