В коллекциях Backbone.js не обязательно должны храниться объекты одного типа. Если в неё явно добавить экземпляр класса, унаследованного от Backbone.Model
, то он без изменений будет помещён в неё. У коллекции есть атрибут model
, в котором хранится конструктор модели. Когда в коллекцию добавляется простой объект, то он в качестве параметра передаётся в этот конструктор.
В атрибуте
model
можно, фактически, указать любую функцию. Возвращаемые значения (экземпляры классов, унаследованных от Backbone.Model
) будут помещаться в коллекцию. Такие функции ещё называют фабриками или фабричными методами. В документации к атрибуту model
как раз представлен вариант такой фабрики.
Чтобы каждый раз не писать однотипных проверок в подобных ситуациях, я предлагаю пользоваться паттерном «Фабрика фабрик»:
App.Factory = function (getter, hash, def) {
return function () {
var value = getter.apply(this, arguments);
var ctor = hash[value] ? hash[value] : def;
return new ctor(arguments[0], arguments[1]);
};
};
- getter — функция, которая возвращает значение, на основании которого будет выбираться требуемый конструктор;
- hash — объект ключ-значение с перечислением конструкторов, которые могут использоваться фабрикой;
- def
— конструктор по-умолчанию.
Предположим, что в коллекции могут находиться объекты следующих классов:
App.Item = Backbone.Model.extend({});
App.ItemNews = App.Item.extend({});
App.ItemAction = App.Item.extend({});
App.ItemMessage = App.Item.extend({});
Таким образом, фабрика объектов будет выглядеть так:
App.ItemFactory = App.Factory(
function (attr) { return attr.type; },
{
"news": App.ItemNews,
"action": App.ItemAction,
"message": App.ItemMessage
},
App.Item
);
App.Factory
возвращает функцию, которая, в свою очередь, будет возвращать требуемый экземпляр в зависимости от значения атрибута type
. Эту функцию и передаём в описание коллекции.
App.Items = Backbone.Collection.extend({
model: App.ItemFactory
});
Теперь коллекция будет заполняться моделями нужного типа автоматически.
Практическое применение паттерна можно посмотреть в исходном коде примера.