MVC中Model可以使用接口与View通信吗?

Can Model use interfaces to communicate with View in MVC?

在经典的 MVC 模式中,模型通过通知事件与视图通信。

不过好像给视图定义一些基本的接口,让模型通过接口与视图通信,也是可行的,而且还是可以解耦模型和具体视图的。

但是,我从未听说过在视图和模型之间使用接口的任何 MV* 模式。这样交流有什么障碍吗?

MVC 是如何工作的?

首先,MVC is an architectural pattern:它描述了系统的主要部分,它们的职责以及它们如何相互作用。它不强加任何特定的实现。

original MVC for example was designed in 1979 by OOP pioneers in a Smalltalk 上下文。在这种动态类型语言中,没有接口:对象与向它们发送消息的其他对象通信,甚至不确定接收方是否可以处理消息。

视图负责显示模型的某些内容。但是对于视图来说,连续查询模型以查看发生了什么变化是非常低效的。因此,MVC 使用推送模型:视图可以查询模型以显示一些内容,但是模型向视图广播发生了更改并且值得考虑刷新显示。

不同的视图可能显示不同的内容。假设模型是汽车的 digital twin。一个视图可以只显示速度,就像它会出现在仪表板上一样。另一个视图可以忽略速度,只以 3D 方式绘制汽车。为了避免模型必须知道每种可能的视图的所有内部细节,广播保持简约。

观察者和通知

notify() 消息就是这种极简主义的交流方式。

GoF popularized design patterns and started their book with decomposing the different features of MVC into different independent patterns. The subscribe/notify relationship between view and model was mapped to the observer pattern。由于它们的设计非常适合强类型语言,因此 notify()/update() 变得非常流行。

该模式的工作原理如下:

  • 模型(“主题”)的非常不同的观察者(“视图”)都使用相同的接口,该接口定义了所有视图共有的方法。在 GoF 中,他们使用抽象 Observer class。然而,在许多现代语言中,倾向于用 interface.
  • 代替抽象的 class
  • 对象(模型)的观察者(视图)subscribe/register,它跟踪所有已注册的对象。
  • 每当模型发生变化时,模型都会触发一个广播,通知所有观察者发生了某些变化 (notify()/update()),但不会准确说明是什么。

备选方案?

接口就像空壳,隐藏了其中的内容。它们本身不足以定义一个全面的解决方案;它们只是拼图的一部分:

  • 如果你使用带有显式接口的语言,如Java(interface)或Swift(protocol),一旦定义了接口,你需要定义class实现它们的 es。
  • 如果您使用带有隐式接口的语言,例如 C++ 或 JavaScript,您已经有了实现,但您仍然需要找到一种方法让模型通知其所有视图。

在这两种情况下,拥有接口可以让模型和视图相互理解。但是要进行 MVC 广播,模型需要知道向谁通知更改,而视图必须知道要听谁的。

所以你最终会得到类似于观察者的东西。
现在传统的观察者模式并不是唯一可能的解决方案。你可以想到:

  • 一个更具体的界面:观察视图不会有一个单一的方法来通知某些事情发生了变化,而是有特定的方法也可以告诉发生了什么变化(例如onSpeed()onShape()) .视图可以更有效地做出反应。唯一的问题是视图被迫实现他们绝对不感兴趣的方法(即没有 interface segregation
  • 更智能的通知:模型会给出一些关于模型中修改内容的提示。例如,它可以是通过 notify()
  • 提供的已更改模型对象的列表
  • 更精细的订阅:视图可以订阅已知模型组件,而不是订阅完整模型。但这会让我复杂得多。
  • a pub/sub 基于事件的设计:模型将在队列中发布特定的变化事件(例如“改变速度”、“改变形状”)(甚至可能有额外的信息。视图可以订阅queue,忽略不相关的变化事件,处理剩下的。