使用MVC / Backbone.js实现复合模式

时间:2012-01-16 22:54:00

标签: javascript model-view-controller design-patterns backbone.js composite

我的webapp有一个复合结构,即每个Category集合可以包含单个Items和其他Categories的混合作为其行/节点/子节点(这里不确定正确的术语)。实际上,它比这更简单,因为每个集合都由一个模型Category表示,所以基本上每个Category集合都有Item模型和Category模型作为它的子项。

一般来说这是使用MVC实现此结构的可行方法吗?更具体地说,在Backbone.js中,集合是否可以拥有模型工厂(获取json并根据json的结构计算生成哪个模型)而不是静态模型属性?

4 个答案:

答案 0 :(得分:5)

我假设您在JSON中收到的类别/项目列表看起来像这样......

{
    'id': 1,
    'name': 'My 1st Category',
    'children': [
        {
            'id': 2,
            'name': 'My 2nd Category',
            'children': []
        },
        {
            'id': 1,
            'name': 'An Item',
            'price': 109.99
        }
    ]
}

Backbone.js没有开箱即用的支持集合中多个模型的东西,但它对你在集合中放置的模型类型也没有任何限制。

在集合定义中指定模型类型只做一件事,如果将原始JSON传递给集合而不是Backbone.Model对象,它可以让Backbone知道要创建的模型类型。如果您将Item模型添加到已包含少量Category模型的集合中,Backbone将没有问题将其弹出到模型列表中;它不进行任何类型检查。

因此,考虑到这一点,您可以使用集合提供的所有内容,除非传递原始JSON;你需要自己处理。因此,您可以选择预先构建模型,将它们转换为Backbone.Model个对象,或者创建一些可以为您解析的内容。

对于第二个选项,解析器,我建议将一个特殊变量传递给包含原始JSON的集合,然后在initialize函数中处理它。这是一个例子:

var CategoryCollection = Backbone.Collection.extend({
    initialize: function(m, models) {
        _.each(models, function(model) {
            var modelObject = null;
            if (model.price !== undefined) {
                modelObject = new Item(model);
            } else {
                modelObject = new Category(model);
            }

            this.add(modelObject);
        }, this);
    }
});

所以它有点hacky,但你根据它是否有一个特定字段(在我的例子中为price)确定模型的类型,创建模型对象,然后将其添加到集合中。

然后你会这样称呼它:

var myCollection = new CategoryCollection([], myJSON);

请注意,您必须传递一个空数组作为第一个参数,因为您通常会将一组模型传递给集合。

稍后使用该集合时,您可以使用简单的Item支票确定您是在处理Category还是instanceof

_.each(myCollection.models, function(model) {
    if (model instanceof Item) {
        console.log("It's an Item! Price: ", model.get("price"));
    } else {
        console.log("It's a Category!");
    }
});

答案 1 :(得分:1)

是的,你可以。我以前做过。我认为此链接可以帮助您:http://documentcloud.github.com/backbone/#Collection-model

以下是我用于项目的主要脚本之一:https://gist.github.com/b65893e0c2e3c46d3dc1

答案 2 :(得分:1)

通过覆盖检索和保存模型数据时骨干网内部使用的内置公共方法parsetoJSON,可以相当简单地实现。

首先,当您从数据库中检索模型时,您应该覆盖模型的parse方法,以创建表示示例中给定项的模型。

然后在保存时,toJSON方法用于将数据序列化回服务器可以理解的内容 - 您只需在每个项目的模型上调用toJSON方法将其序列化为格式后端会认出来的。如果查看Backbone.sync的代码,如果没有传递自定义数据,您将看到模型总是使用toJSON进行序列化。

如果您需要更详细的信息,请告诉我,但我相信您应该可以从这里获取信息!

答案 3 :(得分:1)

是的,您可以使用工厂方法模式在骨干集合中创建模型。假设@kpeel's answer中建议的数据结构,您可以定义

// Factory method
var CategoryOrItemFactory = function(data, options) {
    if (data.children) {
        return new Category(data, options);
    } else {
        return new Item(data, options);
    }
};

// Model definitions
var Item = Backbone.Model.extend();

var Category = Backbone.Model.extend({
    initialize: function() {
        this.children = new Children(this.get("children"));
    }
});

var Children = Backbone.Collection.extend({
    model: CategoryOrItemFactory
});

然后,您将创建根项(类别)并创建完整的数据结构:

// create the root item
var rootItem = new Category(rawData);

访问类别的子项children属性,例如

  rootItem.children.get(2).get("name");

以下是jsFiddle with the above code