【问题标题】:Which architectural pattern allows dynamic instantiation of multiple views per model?哪种架构模式允许每个模型动态实例化多个视图?
【发布时间】:2014-08-19 04:00:27
【问题描述】:

假设我想构建一个日历应用程序(在 HTML + JS 中),用户可以一次看到一周。

用户应该能够定义事件,例如周一 1:00 - 3:00:

         +---------+---------+     +---------+
         | Monday  | Tuesday | ... |  Sunday |
         +---------+---------+     +---------+
0:00     |         |         |     |         |
         +---------+---------+     +---------+
1:00     ///////////         |     |         |
         //MyEvent//---------+     +---------+
2:00     ///////////         |     |         |
         +---------+---------+     +---------+
...                                   
         +---------+                  ...
23:00    |         |   ...
         +---------+

我考虑过创建一个模型EventModel 和一个视图EventView,并通过通常的MVC 方法将它们连接起来。 eventView 将作为单独的图层呈现在日历网格的顶部,因此它能够自主保持其大小和位置。
EventModel 只有三个属性,startTimedurationtitle

如果用户定义一个跨越午夜的事件,例如周一 23:00 至周二 2:00,事情就会变得更加困难:

         +---------+---------+     +---------+
         | Monday  | Tuesday | ... |  Sunday |
         +---------+---------+     +---------+
0:00     |         ///////////     |         |
         +---------//MyEvent//     +---------+
1:00     |         ///////////     |         |
         +---------+---------+     +---------+
2:00     |         |         |     |         |
         +---------+---------+     +---------+
...                                   
         +---------+                  ...
23:00    //MyEvent//   ...
         +---------+

现在需要绑定到同一个模型的两个视图。

当然,模型中的所有更改都应反映在视图中。请注意,随着startTimeduration 属性的更新,单个模型所需的视图数量可能会发生变化(1 到 7)。

换句话说:模型中的更改需要触发该模型的视图实例化/销毁。

我看到了两种可能的方法来实现这一点:

  • 使用一些控制器逻辑来动态生成/删除所需数量的视图和模型,并保持模型彼此同步

...这似乎是个坏主意,因为这需要大量的摸索以及额外的模型类别。

  • 坚持使用一个模型并构建一个类似于一个视图的视图代理,但在内部控制所需的“子视图”数量。

第二种方法对我更有吸引力。我写了一些伪代码来说明它:

ViewProxy.onModelChange(model) {
    if (model.hasChanged("startTime") or model.hasChanged("duration"))
        this.destroySubviews()
        subStartTimes[] = getSubStartTimes(model.startTime, model.duration)
        subDurations[] = getSubDurations(model.startTime, model.duration)
        subViews[] = this.buildSubviews(subStartTimes, subDurations)
        subViews.bind(model, "title")
    endif
}

这样做的缺点是子视图不必要地被销毁并在所有模型更新上重新构建(仅title 除外),除非我包含额外的逻辑 - 这不是那么微不足道。另外,这个代理是控制器和视图之间的一些奇怪的东西,这让我感到不舒服。

所以我的问题是:是否有解决此问题的标准方法?如果不是,上述解决方案可能会出现哪些问题?还有其他解决方案吗?

【问题讨论】:

  • 该模式称为“MVC”(与您现在似乎正在实施的类似 Rails 的结构相反)。模型应该是以后的应用程序。有点像视图、模板、表示对象和控制器都包含在表示层中。
  • 任何使用模板引擎或“非模板引擎”(例如视图中的 php 代码作为视图类的一部分)的任何 MVC 都将支持您从控制器/模型传入参数,然后允许您要使用此信息来构建视图,但是您想使用包含或仅处理与 php 相同的值,而不是从控制器或模型传入它需要的值,一些 MVC 支持您从模型加载视图并将其作为 html 返回,所以如果视图在做应用层的事情,它可以是模型的一部分。
  • 我知道我使用 php 作为示例的注释,但这适用于 Java 中的任何内容,例如,您的模板可以是您的标准窗口,也可以是模型/控制器中的窗口组件。

标签: model-view-controller


【解决方案1】:

您的EventModel 映射到多个视图元素,因为您的模型包含多个子元素 (EventDayModel)。

当然,EventModel 的输入定义可能是 titlestartDateTimeduration,但该模型在概念上由一个或多个 EventDayModel 元素组成(每个元素都包含一个 startTime 和 @987654329 @)。

因此,与其维护EventModelEventViewProxy 之间的一对一映射(有效地控制每天对应的视图元素),不如将EventModel 细分为EventDayModel 列表, 每个都与 EventDayView 元素具有一对一的映射关系。

当您更改EventModel 时,会重新计算EventDayModel 列表并更新相应的EventDayView 元素。

【讨论】:

  • 好的,但是谁或什么负责其他视图的实例化/销毁?请记住,1 个 EventModel 可能对应于 1 到 7 个 EventDadModel 实例,具体取决于 startDateTimeduration。在一天结束的时候,你会得到像 EventViewProxy 之类的东西
  • 好吧,假设您使用的是 MVC 框架,那么 MVC 框架负责。例如,使用AngularJS,您将使用ng-repeat 绑定event.evenDays 列表,以便每个eventDay 都显示在视图元素中(例如<div>)。如果列表发生变化,AngularJS 添加/删除视图元素。
  • 尝试使用 AngularJS 编写代码。这可能是可能的,但我找不到办法。
【解决方案2】:

搜索了一会,发现答案是The Composite Pattern

因此,想法是将一个事件的所有事件视图 sn-ps 视为管理多个子视图的单个视图。 至于数据绑定,我想这在视图中没有一点逻辑是不可能的。就我而言,我决定视图本身将由较小的 MVC 层次结构组成(想想 Composite 模式!)。因此视图内部的模型通过简单的数据绑定与子视图绑定,ViewProxy 管理底层模型中的更新。

【讨论】:

    【解决方案3】:

    您可以模拟 Google 日历结构,该结构重新呈现日历,而不是破坏和重新创建子视图。

    如果您使用 Angular,那么您可以绑定范围变量并监视模型属性以更新视图属性。

    每个视图都可以看作是根据开始和结束时间定位的“div 框”。如果用户删除事件,则关联的“div 框”和事件对象将从事件列表中删除。

    如果有 to 事件的更新,那么我们会根据开始和结束时间更新“div box”的坐标。

    下面的资源是展示谷歌日历使用的模型结构。

    https://developers.google.com/resources/api-libraries/documentation/calendar/v3/java/latest/com/google/api/services/calendar/model/package-summary.html

    【讨论】:

    • 不确定如何回答问题
    • 我查看了 Google 日历 Web 应用程序,发现他们显然通过将整周视为一个视图来规避问题。因此,每次更改事件时,都会重新渲染整个日历。这不是我想要的;)
    • 对于之前不完整的答案,我深表歉意,因为我忙于其他一些活动,请参阅我的更新答案 - 澄清。
    猜你喜欢
    • 2014-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-20
    • 2011-05-22
    • 1970-01-01
    • 1970-01-01
    • 2011-08-24
    相关资源
    最近更新 更多