0

一个用户故事:

我们应用程序的用户创建了公路旅行。Aroadtrip是一系列有趣的目的地。每个destination人都有一些关于在那里看到的活动或景点的细节。通过这种方式,我们的用户定义了两次公路旅行,其中每次旅行都有一些独特的目的地和一些共同的目的地——例如,两次旅行都包括史密森尼博物馆。该应用程序在内存中维护所有更新,并且仅在用户单击保存时才提交到数据库。用户主动更新两个行程,可以随意切换。在我们的应用程序中,我们正在处理史密森尼目的地,但有时我们需要向上导航我们的对象层次结构,从目的地到其包含的公路旅行。问题是目的地参加了两次公路旅行。

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

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

我们可以使用什么好的设计模式或数据结构来允许向后导航,同时确保我们只有一个目标对象的副本?

要求:

  1. 您的模型涉及多对多关系。
  2. 在内存中仅表示所有模型一次(身份映射)。
  3. 您的数据结构应该易于导航。您不仅可以从父级导航到子级,还可以从子级导航回到最初获取子级的父级。
  4. 我想避免向数据模型引入额外的模式。

到目前为止,我最好的想法是用上下文对象包装每个目标对象(类似于链表包装节点的方式)。上下文对象将维护一个指向最初从中获取它的父对象的指针。我们将始终通过其包装器处理每个目的地。我相信这将是代理模式或装饰器模式(我倾向于代理)。(这与 jQuery 对象包含许多元素并且多个 jQuery 对象共享对相同元素的引用的方式本质上不是相同的想法吗?)

我考虑维护一个“当前公路旅行”上下文变量,并将其用于从目的地导航到其包含的公路旅行。这不如实际的“获取上下文”可靠。事实上,这是一种完全不同的策略,我不确定我是否喜欢它。

我记得 ActiveRecord 也有同样的问题(尽管我已经有一段时间没有使用它了)。在 AR 中,如果我从 RoadTrip1 开始,然后获取它的目的地,我就不能很好地从目的地导航到公路旅行(通过某种获取上下文)。相反,我会考虑父母双方(公路旅行),并且没有迹象表明我是如何到达那里的。对?

其他人之前是否遇到过这个问题 - 也就是说,想要向后导航,而向后导航被许多父母混淆了?你有没有问过“我是从哪个家长那里来的?” 你是怎么回答的?

4

2 回答 2

0

您必须有 3 个课程:Roadtrip、Destination 和 Place。所以你的目的地 A 和 B 是两个不同的对象,它们都指向同一个地方。

于 2011-09-16T15:16:21.610 回答
0

在使用代理模式后,我能够制定出我的解决方案。我真正想要的是“获取上下文”的概念。我想知道我最初从哪个父母那里获取模型(一个有多个父母的孩子)。

解决问题的关键是意识到维护获取上下文是我们的查询对象而不是我们的模型的责任。

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

我们从一个roadtrip模型开始并调用该destinations函数。此函数返回一个查询对象。这个查询对象在设计上与 Rails 的 Arel 实现相似,因为它是惰性的,在调用allfirsteach等之前实际上不会返回任何记录。查询对象有一个context变量指向它的父对象——roadtrip模型。

all调用返回一个集合对象,该对象context指向调用它的查询。queried item集合中的每个项目都是包装每个底层destination模型的代理 (a )。代理维护对其集合的引用。实现此代理的最简单方法如下:

var proxied_destination = Object.create(destination);

通过这种方式,您可以将 分配context给代理而不影响原始。

proxied_destination.context = collection;

这允许“主”模型保持不变,从而进行身份映射。如果我们的模型保持对其集合的直接引用,这是不可能的,因为模型可以参与多个结果集(我们可以运行任意数量的查询),并且在我的场景中,我们只期望一个上下文(父级)。

我们调用activitieswhich 为我们提供了另一个查询对象,其上下文是被代理的destination。我们调用first而不是获得一个集合,而是获得一个代理,该代理activity具有指向活动查询对象的上下文。

因此,使用代理可以让我们指向并因此“爬升”对象层次结构,同时仍然保持身份映射模型,这些模型仍然忽略该层次结构并且可以轻松地参与多个集合(结果集)。

于 2011-09-19T14:38:58.813 回答