在Backbone中保存对全局集合的引用的最佳模式



我正在开发一个木偶应用程序,但主题也涉及raw Backbone。

在我的应用程序中,我有很多收藏。其中,有3个重要的,在整个应用程序中使用(例如用户数据,如名称,它显示在大多数视图中)。主要的问题是:在Backbone/Marionette中保持对集合的引用的最好方法(一个好的模式)是什么?以下是我的一些想法:

  • 我应该将它们附加为Application对象的属性吗?如果是这样,我必须将Application对象的引用传递给所有视图,然后视图传递给它们的子视图,子视图传递给子视图,等等。但这似乎是一个蹩脚和丑陋的设计。
  • 相反,我可以单独传递每个集合,但这似乎是更糟糕的解决方案,因为我无法预测哪个(子)视图将需要集合。保持这些嵌套引用的顺序将比传递Application对象困难得多,我可以传递一次,总是。
  • 也可以将Application作为单例导入。我使用requireJS,现在大多数模块返回构造函数(视图,模型和集合的构造函数)。现在app模块返回的是Application构造函数,但它可以返回Application对象。然后,如果视图需要从集合中显示一些数据,它可以只需要app模块,这就是全部。
  • 最后,基于前面的观点,我认为我可以创建一个集合的普通映射,并使其像以前一样成为单例。这只是为了禁止所有的视图访问Application对象,这似乎仍然是一个糟糕的模式。

请提出你认为最好的建议(也欢迎上面的评论点)。我只需要一个好的设计模式。据我所知,木偶文档在这里没有任何建议。

我遵循David Sulc的书《backbone . marionetie .js: A Gentle Introduction》中的建议。(下一本书也介绍了如何用require https://leanpub.com/structuring-backbone-with-requirejs-and-marionette)The构建相同的项目,他使用的代码示例可以在github上找到,所以你可以看看最后的例子,如果你不想买这本书,但我真的推荐它,因为它真的帮助了我如何构建我的项目。

首先,我设置了一个实体模块。文件的结构也遵循如下:我有一个实体文件夹,其中有单独的实体。

每个实体文件涉及该特定实体的所有操作和结构。我喜欢这种方法,因为当我想编辑实体结构或从服务器获取数据的方法时,我只需要去一个地方进行此更改。

与实体的交互通过牵线木偶请求/请求系统处理。通过这种方式,你可以将处理程序暴露给应用程序的其他部分,但它们不需要关心如何处理该请求,只要它带回所需的响应即可。

下面是我的一个实体的例子来展示我的意思-我的应用程序需要一个名为position的集合,在不同的阶段,所以这是在应用程序的早期加载的东西,然后在它的整个生命周期中可用。

 //i am using require so i define my app to use
 define(["app", ], function(MyApp) {
     //All of this will be added to the Entities module so if i want direct access 
     //i can go Myapp.Entities.whateverEntityIhaveDeclared
     MyApp.module("Entities", function(Entities, MyApp, Backbone, Marionette, $, _) {
         //model (nothing new here)          
         Entities.Position = Backbone.Model.extend({
             urlRoot: "api/positions",
             defaults: {
                 name: "",
             }
         });
         //collection again nothing new here
         Entities.PositionCollection = Backbone.Collection.extend({
             url: "api/positions",
             model: Entities.Position,
             comparator: "name"
         });
         //an init function to attach a position collection onto Entities module so it can be available throughout my app
         var initializePositions = function() {
             if (Entities.positions === undefined) {
                 Entities.positions = new Entities.PositionCollection();
             }
         };
         //
         var API = {
             //returns a jquery deferred promise so that this request can easily be handled async
             loadPositionEntitiesRemote: function() {
                 //init positions make's sure i have the collectoin avaliable if it
                 //has not yet been defined
                 initializePositions();

                 //setup defer object
                 var defer = $.Deferred();
                 //I actually use a custom sever object here when dealing 
                 //with ajax requests
                 //but because my app always go through this API i can 
                 //easily swap out  how the collection is retrieved.
                 // Here is an example using backbones fetch
                 Entities.positions.fetch({
                     success: function() {
                         defer.resolve();
                     },
                     error: function(data) {
                         defer.reject(data);
                     }
                 });
                 //setup promise to return
                 var promise = defer.promise();
                 return promise;
             },

             //get the positions collection from here i could 
             //directly access the attributes or add to the collection
             refrencePositionEntities: function() {
                 initializePositions();
                 return Entities.positions;
             },
             //get a position from the collection based on id
             //
             getPositionEntity: function(positionId) {
                 initializePositions();
                 return Entities.positions.get(positionId);
             }
         };

         //setup handlers for the app to use
         MyApp.reqres.setHandler("position:entities:remote", function() {
             return API.loadPositionEntitiesRemote();
         });
         MyApp.reqres.setHandler("position:entities:refrence", function() {
             return API.refrencePositionEntities();
         });
         MyApp.reqres.setHandler("position:entity", function(id) {
             return API.getPositionEntity(id);
         });
         MyApp.reqres.setHandler("position:entity:new", function(position) {
             return new Entities.Position(position);
         });
     });
     return;
 });

现在在我的应用程序中使用这个这里有一个例子,现在可以使用

 someFunction: function(){

    //so early in the app i will get the positions
    var positionPromise = MyApp.request("position:entities:remote");
    $.when(positionPromise).done(function() {
                     //do what ever as data has been loaded
                 }).fail(function(data){
                  //something failed so handle here might through up an error page but up to you
                 }).always(function(){
                  //something to always do no matter if fail or sucess
                 });
 }
 anotherFunction: function(){

 //later in the app in another controller i might to get the collection
 // I could also get it through MyApp.Entities.positions but i rather use the
 // API set up so if i ever decided i want to add so checks or something in
 // when retrieving the collection its super easy
 var positionsCollection = MyApp.request("position:entities:refrence");

 }

不确定我是否做了一个很好的工作来解释这一点,但如果你正在寻找一个好的设计的想法在木偶检查这本书,因为它解释这比我刚刚做的要好得多

最新更新