0

ユーザーのストーリー:多対多関係を逆方向にナビゲートするためのパターン/構造体?

私たちのアプリのユーザーは、道路トリップを作成します。 roadtripは、一連の興味深い宛先です。各destinationには、そこに見える活動や見通しについての詳細がいくつかあります。このようにして、ユーザーは2つのロードトリップを定義します。各ロードには、それぞれに固有の目的地と目的地があります。両方の旅行にスミソニアンが含まれています。アプリはメモリ内のすべての更新を保持し、ユーザーが保存をクリックしたときにのみデータベースにコミットします。ユーザーは両方のトリップを積極的に更新し、自由に切り替えを行うことができます。私たちのアプリのポイントでは、スミソニアンの目的地を扱っていますが、目的地からロードトリップを含むオブジェクト階層までナビゲートする必要があることがあります。問題は、目的地が2回のロードトリップに参加することです。

RoadTrip1 
| 
+-Destination1 
+-Destination2 
+-Destination3 
+-Smithsonian (A) //Navigate up to RoadTrip1 

RoadTrip2 
| 
+-Destination4 
+-Smithsonian (B) //Navigate up to RoadTrip2 
+-Destination5 

宛先オブジェクトのコピーが1つしかないことを保証しながら、後方ナビゲーションを可能にするために使用できる、良いデザインパターンまたはデータ構造とは何ですか?

要件:

  1. あなたのモデルは多対多の関係に関与しています。
  2. すべてのモデルをメモリ内で一度だけ表現する(アイデンティティマップ)。
  3. あなたのデータ構造は容易に移動可能でなければなりません。親から子までナビゲートできるだけでなく、その子から元のフェッチ先の親までナビゲートすることができます。
  4. データモデルに追加のスキーマを導入しないようにしたいと思います。

これまでのところ、各宛先オブジェクトをコンテキストオブジェクトでラップすることをお勧めします(リンクされたリストがノードを折り返す方法と同様です)。コンテキストオブジェクトは、それが最初にフェッチされた親へのポインタを維持する。私たちはそれぞれの宛先を常にそのラッパーを通して処理します。私はこれがプロキシまたはデコレータパターン(私はプロキシに傾いている)のいずれかと考えています。 (これは本質的に、jQueryオブジェクトが多くの要素を包含する方法と同じ考えではないでしょうか?複数のjQueryオブジェクトは同じ要素への参照を共有していますか?)

「現在のロードトリップ」コンテキスト変数を維持し、目的地からその道路トリップを含むまで。これは、実際の "取得コンテキスト"ほど信頼性がありません。実際、それはまったく違うタックで、私はそれが好きであるかどうかはわかりません。

私はActiveRecordと同じ問題があることを覚えています(私はそれを使ってからしばらくしていますが)。 ARでは、RoadTrip1で開始してその目的地を取得した場合、目的地からロードトリップまで何らかの種類のコンテキストを介してナビゲートすることができませんでした。代わりに、私は両方の両親(ロードトリップ)を考慮する必要があり、どのように私がそこに着いたかについての指標はありません。右?

前にこの問題に遭遇している人はいますか?つまり、後方のナビゲーションが多くの親によって混乱している場合、後方にナビゲートしたいのですか?あなたは「ここに親がどこから来たの?」と尋ねたことはありますか?あなたはどう答えましたか?

答えて

0

私はプロキシパターンを使用した後のソリューションを処理することができました。私が本当に欲しかったのは、「コンテキストを取得する」という概念でした。どの親から私が最初にモデル(複数の親を持つ子供)を取得したのかを知りたかったのです。

問題を解決する鍵は、私たちのモデルではなく、クエリオブジェクトの責任であるフェッチコンテキストの維持を実現することでした。

var activity = roadtrip.destinations().all().activities().first(); 

我々はroadtripモデルで始まり、destinations関数を呼び出します。この関数は、クエリオブジェクトを返します。このクエリーオブジェクトは、怠け者であり、allfirsteachなどを呼び出すまで実際にはレコードを返さないという点で、RailsのArel実装と似ています。contextの変数はroadtripです。

all呼び出しは、呼び出されたクエリを指しているcontextというコレクションオブジェクトを返します。コレクション内の各アイテムは、基になる各destinationモデルをラップするプロキシ(queried item)です。プロキシはそのコレクションへの参照を保持します。このプロキシを達成するための最も簡単な方法は、それほどのようなものです:あなたが元に影響を与えることなく、プロキシにcontextを割り当てることができます。このように

var proxied_destination = Object.create(destination); 

proxied_destination.context = collection; 

これにより、「マスター」モデルは変更されずにアイデンティティがマッピングされます。これは、モデルが複数の結果セットに参加することができ(私たちが望むだけ多くのクエリを実行できるため)、私たちのモデルがコレクションに直接参照を保持していれば可能ではないでしょう。

activitiesと呼びます。これは、コンテキストがプロキシのdestinationである別のクエリオブジェクトを提供します。 firstと呼びます。コレクションを取得するのではなく、アクティビティクエリオブジェクトを指すコンテキストを持つプロキシのactivityを取得します。

このように、プロキシを使用することで、オブジェクト階層を「登る」ことができ、その階層に気付かずに複数のコレクション(結果セット)に簡単に参加できるアイデンティティマップモデルを維持できます。

0

Roadtrip、Destination、Placeの3つのクラスが必要です。あなたの目的地AとBは、両方とも同じ場所を参照する2つの異なるオブジェクトです。

+0

これは完全に機能し、良い選択です。ありがとうございました。これはラッパーオブジェクトとして別のモデルを使用するだけですが、多対多リレーションシップを逆方向に移動するたびに追加のスキーマを定義する必要があります。私はスキーマを必要としない何かを使ってこれをメモリー上で行う手段を望んでいます。 (私は実際にRoadTripアプリを持っていません。実際の問題ははるかに精巧で、単純なイラストだけが必要でした。) – Mario

+0

あなたが記述する方法で非永続モデルを使用することは可能でしょう。 – Mario

+0

要件4を追加しました。 – Mario