哪种架构模式允许每个模型动态实例化多个视图?

时间:2014-08-19 04:00:28

标签: model-view-controller

假设我想构建一个日历应用程序(在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)。

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

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

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

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

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

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

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除外),除非我包含额外的逻辑 - 这不是那么简单。此外,这个代理在控制器和视图之间是一些奇怪的事情,这让我感到不舒服。

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

3 个答案:

答案 0 :(得分:1)

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

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

因此,不是在EventModelEventViewProxy之间保持一对一的映射(有效控制与每一天相对应的视图元素),为什么不将EventModel细分为EventDayModel列表,每个列表都与EventDayView元素进行一对一映射。

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

答案 1 :(得分:0)

经过一段时间的搜索后,我发现答案是The Composite Pattern

因此,我们的想法是将一个事件的所有事件视图片段视为管理多个子视图的单个视图。 至于数据绑定,我想如果没有视图中的一点逻辑,这是不可能的。在我的例子中,我认为视图本身将由较小的MVC层次结构组成(想想 Composite 模式!)。因此,视图中的模型通过简单的数据绑定绑定到子视图,ViewProxy管理底层模型中的更新。

答案 2 :(得分:-2)

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

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

根据开始和结束时间,可以将每个视图视为“div box”。如果用户删除了该事件,则会从事件列表中删除关联的“div box”和事件对象。

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

以下资源是显示Google日历使用的模型结构。

  

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