今日は、 コレクションを扱う独創的な方法についてお話しします。
コレクションがモデルとして使用されるモデルビューバンドルの一般的な動作は、それらの一定の同期です。 この場合、スキームは少なくとも2つのレベル(コレクションと要素)で取得されます。
モデル | 提出 |
収集 | リスト、表 |
コレクションアイテム | リスト行、テーブル |
コレクションにアイテムを追加しました-すぐにリストに行を追加する必要があります。 コレクションからアイテムを削除しました-リストから対応する行をすぐに削除する必要があります。 などなど。
コレクションはどのように機能しますか? 通常、プログラマには、次のような些細なイベントをサブスクライブする機会が与えられます。
- 追加 (挿入された要素)
- 削除済み (アイテムは削除済み)
- 置換 (指定されたセルのアイテムを置換)
- 移動 (アイテムをある場所から別の場所に移動した)
- クリア (すべてのアイテムを削除)
パフォーマンスの低下を回避するためのより高度な実装には、イベントも含まれます。
- 再注文 (ソート済みアイテム)
- フィルター済み (フィルター済みアイテム)
- リセット (コレクションを任意に変更)
モデル表現接続に関するすべての考慮事項は、モデルコントローラー接続にも当てはまります。 1つのモデルに複数の表現がある場合、複雑なシステムを実装するときに2番目の束が必要です。
簡単な例を考えてみましょう。 LiveJournalのAJAXバージョン、つまり、ページをリロードせずにページの公開、編集、コメントなどを行うブログを作成するとします。 コレクションの例として記事のリストを取り上げてください。 記事は公開日ごとに明確に並べられています。つまり、各記事には独自のインデックスがあり、一般的なリストに含まれています。 最も古い記事のインデックスは0で、最新のNは1です。Nは記事の数です。 すべての記事にはいくつかの表現があることに注意してください。
- ブログの主要部分の記事の要約
- このページのリスト(サイドバー)
- この記事は、タグのリストの表示に影響します。
- 記事はカレンダーの表示に影響します
著者が記事を公開すると、その記事はリストの最後に追加されます。 その後、「added」イベントがパラメーター(index = N)でスローされます。これは、要素がインデックスNの要素の前に追加されたことを意味します。 コレクションの最後。 コレクションに要素を挿入した後にイベントがスローされるため、クライアントはインデックスによってコレクションから記事をリクエストすることで記事のコンテンツを取得できます。 このイベントをキャッチすると、ブログの主要部分に新しい記事の簡単な概要が表示され、「このページで」新しい行が追加され、タグのサイズが変更され、カレンダーが日付の1つをリンクに変換します。
作成者が記事を削除すると、その記事はコレクションから取得され、その後のすべての要素が1つのインデックスに戻されます。 その後、「removed」イベントがパラメーター(インデックス、記事)と共にスローされます。 つまり、イベントが処理されている間、アーティクルはアーティクルパラメーターでまだ有効であるため、クライアントはこのアーティクルを分析でき(たとえば、ラベルと日付を参照)、アーティクルの処理後に削除され、メモリがクリアされます。 このイベントをキャッチすると、ブログの主要部分と「このページ」リストで対応する行が削除され、ラベルのサイズが変更され、カレンダーが日付へのリンクを削除します(その日他の記事が公開されていない場合)。
作成者が記事を変更すると、コレクションの最後にスローされ、その結果「moved」イベントがスローされ、ビューは何らかの方法で再び更新されます。
まあなどなど...
一般に、コレクションは変化しており、そのことをすべての人に通知します。また、ブログのWebページの変更に対する責任はプレゼンテーションクラスにあります。 それがMVCスキームが私たちに指示していることです。
注: 「更新」イベントもある場合があります-要素を変更しました(完全に置き換えられず、既存の要素の一部のプロパティを変更しただけです)が、このイベントはコレクションではなく要素自体でリッスンする必要があると思います。 このイベントを自動化すると、パフォーマンスが大幅に低下します。
次に、最も一般的に使用される最初の5つのイベント、追加、削除、置換、移動、クリアに焦点を当てます。
アーキテクチャ全体が完全にMVCで構築されている大規模なプロジェクトに携わっており、この分野での経験があります。 これら5つのイベントの処理は通常、ほとんどのビューでまったく同じように行われることを学びました。 さらに、これらのイベントの処理アルゴリズムは互いに強く交差するため、大量の反復コードが発生します。 表現クラスはすぐに面倒で維持が困難でした。
すぐに、ほとんどのビューで、すべてのイベントを処理するのに十分な数個の簡単なスクリプトを要求できることが明らかになりました。 さらに、1つのプレゼンテーションのフレームワーク内のこれらのシナリオは、相互に共通点がなく、完全に特定かつ独立したアトミック操作を実行します。 さらに、すべてのコレクションイベントの処理は、これらの単純なシナリオに基づいて一意に記述され、 すべての表現に対してまったく同じに見えるため、一部の補助クラスで1回のみ実装できます。 この補助クラスは、「戦略」パターンに従って機能します。つまり、アルゴリズムをパラメーターとして受け入れます。これは、各表現に固有の非常にアトミックで独立したスクリプトです。
それで、新しいパターンが生まれました。 「コレクションビューファシリテーター」と呼ぶのは正しいでしょうが、何らかの理由で「同期」が好きです。
一番下の行は次のとおりです。 コレクションの次のプレゼンテーションを実装するために開発者に必要なことは、次のシナリオを定義することだけです。
意味論 | 説明 | 例 |
作成者(データ):表示 | プレゼンテーション要素を作成 | テーブル行を作成 |
インサーター(表示、インデックス) | 指定した場所に既存のビュー項目を挿入します | テーブルに行を挿入 |
リムーバー(インデックス):ビュー | 指定した場所からビューアイテムを削除する | テーブルから行を削除 |
駆逐艦(表示) | ビューアイテムを破棄する | テーブル行を破棄する |
明確な():ビューの配列 | コレクションからすべてのアイテムを削除して返します。 | すべてのテーブル行を削除して返します |
明らかに、これらのアルゴリズムは非常に単純であり、互いに完全に独立しています(おそらく後者を除きますが、最適化に必要です)。 それらを実現することは難しくありません。 ただし、パフォーマンスを損なうことなく、特定のコレクションと同期するには十分です。 標準コレクションイベントの処理がいかにシンプルで効率的かをご覧ください。
- 追加(インデックス、データ)
- ビュー=作成者(データ)
- インサーター(ビュー、インデックス)
- 削除(インデックス、データ)
- ビュー=リムーバー(インデックス)
- 駆逐艦(表示)
- 置換(index、oldData、newData)
- oldView =リムーバー(インデックス)
- 駆逐艦(oldView)
- newView = Creator(newData)
- インサーター(newView、インデックス)
- 移動(fromIndex、toIndex)
- view =リムーバー(fromIndex)
- インサーター(view、toIndex)
- クリア済み()
- views = Clearer()
- foreach(ビューで表示)Destroyer(ビュー)
そして今、私たちはこれらすべてを補助クラスに結合し、喜んでいます! JW.Collection: JW.Syncherに対するこのことの実装を次に示します。 そして、ここに例として考えられるテストがあります: JW.Tests.Util.SyncherTestCase 。
並べ替え、フィルター、リセットされたイベントの解決策を思いつくかもしれませんが、まだ届きません(おそらく、意図した目的に使用することは非常にまれだったためです)。