2013-02-14 4 views
17

私はBackboneアプリケーションを少しずつ開発しており、Require.jsでBackboneを使用する方法を学び始めています。Backbone/Require Applicationでの共有オブジェクトのベストプラクティス

私がリファクタリングしている私のバックボーンアプリでは、App.model.repoのような名前空間を定義しました。このモデルは、さまざまなビューで繰り返し使用されます。私はいくつかのコレクションで同じことをします。たとえば、App.collection.filesです。これらのモデルとコレクションは、最初のインデックスファイル要求でブートストラップされます。

私はthis exampleを見つけました。これは、そのブートストラップされたデータを取得するのに適しています。しかし、これらのモデルとコレクションをビュー間で再利用/共有するには苦労しています。

3つの解決策が考えられます。どちらがベストですか、なぜですか?あるいは、私が完全に欠けている別の解決策がありますか?

溶液1

インデックスでこれらの共通のモジュールおよびコレクションを(それらが中にブートストラップされた場合)を定義し、次いで(initializeの)オプションとして、各バックボーンビューに沿って渡します。

これは分離まではきれいだと思われますが、すばやくファンキーになり、たくさんのものがその場所を通過します。

ソリューション2

globalsモジュールを定義し、それに一般的に使用されたモデルやコレクションを追加します。

// models/Repo.js 
define(['backbone'], 
    function(Backbone){ 
     return Backbone.Model.extend({ 
      idAttribute: 'repo_id' 
     }); 
    } 
); 

// globals.js (within index.php, for bootstrapping data) 
define(['underscore', 'models/Repo'], 
    function(_, RepoModel){  
     var globals = {}; 

     globals.repoModel = new Repo(<?php echo json_encode($repo); ?>); 

     return globals 
    } 
); 

define(['jquery', 'underscore', 'backbone', 'handlebars', 'text!templates/NavBar.html', 'globals'], 
    function($, _, Backbone, Handlebars, template, globals){ 
     var repoModel = globals.repoModel; // repoModel from globals 

     return Backbone.View.extend({ 
      template: Handlebars.compile(template), 
      initialize: function(options){ 

      } 
     }); 
    } 
); 

このソリューションは、AMD全体のポイントを守っていますか?

ソリューション3

(効果的にシングルトンにする)の代わりに、コンストラクタで、いくつかのモデルやコレクションがインスタンスを返してください。

// models/repo.js 
define(['backbone'], 
    function(Backbone){ 
     // return instance 
     return new Backbone.Model.extend({ 
      idAttribute: 'repo_id' 
     }); 
    } 
); 

// Included in index.php for bootstrapping data 
require(['jquery', 'backbone', 'models/repo', 'routers/Application'], 
    function($, Backbone, repoModel, ApplicationRouter){ 
     repoModel.set(<?php echo json_encode($repo); ?>); 

     new ApplicationRouter({el: $('.site-container')}); 
     Backbone.history.start(); 
    } 
); 

define(['jquery', 'underscore', 'backbone', 'handlebars', 'text!templates/NavBar.html', 'models/repo'], 
    function($, _, Backbone, Handlebars, template, repoModel){ 
     // repoModel has values set by index.php 

     return Backbone.View.extend({ 
      template: Handlebars.compile(template), 
      initialize: function(options){ 

      } 
     }); 
    } 
); 

これは私が心配すると、実際にコンストラクタとインスタンスが混乱することがあります。

エンド

あなたがここまで読めば、あなたは素晴らしいです!時間をとっていただきありがとうございます。

+0

私は既存のアプリをリファクタリングして、オプション1と3の両方を試しました。オプション1はすぐに髪の毛ができました。どこでもオプションが渡されました。多くの場合、必要な子モジュールに到達するために、すべてが必要でないモジュールが1つありました。結局、オプション3は私にとってもっときれいだと感じます。 真実、私は現在のプロジェクトでこれら3つのオプションすべてを使用しています。短いライフサイクル要素のオプション1。オプション2は、 "apiUrl"(共通ルートURL)のような単純なものです。プロジェクト規模で使用されるバックボーンモデルとコレクションのオプション3。 – Bart

+0

接線関係:http://stackoverflow.com/a/15528785/158651 – Bart

答えて

4

私の場合、私はオプション3を好んでいます。混乱を避けるために、すべてのシングルトンインスタンスをinstancesという名前の独自のフォルダに配置します。また、私はinstanceモジュールからmodel/collectionを分離する傾向があります。すべてのモジュールは、(例えば、名前空間を介してケースされていない)、その依存関係を定義することを余儀なくされたとして、私は、このオプションを好む

define([ 
    "instance/photos" 
], function(photos) { /* do stuff */ }); 

その後、私はそれらを呼び出します。ソリューション2はその仕事をすることができますが、私がAMDを使用している場合は、モジュールをできるだけ小さくしたいのですが、小さくして単体テストを簡単にしてください。

最後に、単体テストについては、単体テスト内のインスタンスをモックデータを使用して再定義できます。だから、間違いなく、オプション3

あなたは、私がATMに取り組んでいるオープンソースのアプリでこのパターンの例を見ることができます:https://github.com/iplanwebsites/newtab-bookmarks/tree/master/app

+0

私はインスタンスフォルダのアイデアが好きです。それはうまくいくかもしれない。 [this code](https://github.com/iplanwebsites/newtab-bookmarks/blob/master/app/instances/settings.js)を見ると、あなたの 'app'は本質的にあなたの' globals'です?これは**オプション2 **に近いと思われます。 – Bart

+0

はい、いいえ、 'app'はグローバルオブジェクトであり、常に呼び出します。しかし、それは名前空間として使われず、いくつかの汎用ヘルパー関数を返すだけです。 (レイアウトマネージャとi18nライブラリは正常に動作します)。完璧な世界では、私は 'appモジュール'を使用せず、 'require.config'の中にライブラリ設定を設定しますが、残念なことにRequireJSはshimモジュールの' init'しかサポートしません。 –

+1

ああ、ちょうどあなたが意味するものを見た。このプロジェクトが名前空間として 'app'を使っていたことに気づいていませんでした。私は過去にこれをやっていましたが、私はもうこれほど柔軟性がないので、これは一種のものです。 'instances/settings'がどこで使われているかを見ると、名前空間ではなく戻り値だけが使われることがわかります。 –

1

私は、この例レポhttps://github.com/tbranyen/github-viewer

を見てみましょうバックボーンボイラープレートの実用例

バックボーンボイラープレートは、多くの不要な毛羽立ちをしますが、実際には便利ですが、複雑なjavascriptアプリケーションを開発するための一般的なパターンに明確な方向性を示しています。

私は、誰かがそれに私を打つていない場合は、(より具体的に質問に答えるためにしようとすると、今日、後で戻ってくるだろう:)

1

私はそれが一般的にavoidusingsingletonsに良い解決策1.好む、とグローバルを使用することは、特にRequireJSを使用しているため、避けるべきことです。

は、ここで私はソリューションの1のために考えることができますいくつかの利点がある:

それは、ビューのコードが読みやすくなります。最初にモジュールを見ている人は、それが使用するモデルのinitialize関数を見てすぐに見ることができます。グローバルを使用する場合は、ファイル内で500行下にアクセスする可能性があります。

これにより、ビューコードの単体テストを簡単に記述できます。おそらくあなたのテストで偽のモデルを渡すことができます。

+0

素晴らしい点。ありがとう。 – Bart

+1

私は実際にポールの考え方に同意します。 オプション1を使用すると、すべてのコードが複数のモジュールやオブジェクトなどに分割されているため、すべてのバックボーン関連オブジェクトを簡単にテストでき、非常に読みやすくなります。 オプション1に追加したい点バックボーンのpub/subモデルを強化するのに役立つということです。イベント駆動型の使用は、関数を直接呼び出すよりもはるかに優れています! – adrian

+1

私はあなたの可読性の点に同意しません。 this.repoModelはoptions.repoModelに設定されています。私たちには、オプションに何があるのか​​、どのようなoptions.repoModelであるのかを知る方法がありません。 optionsとoptions.repoModelにあるものを理解するために、このモジュールをインスタンス化するコードを追跡する必要があります。私はこの前提の上で少し離れているかもしれませんが、バートがrequireを使用しているので、なぜ関数を通してモジュールを渡すのでしょうか? – andyzinsser

関連する問題