Can Model在MVC中使用接口与View进行通信



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

但似乎为视图定义一些基本接口,并使模型通过接口与视图通信也是可行的,并且仍然可以将模型与具体视图解耦。

然而,我从来没有听说过任何使用视图和模型之间接口的MV*模式。以这种方式交流有什么障碍吗?

MVC是如何工作的

首先,MVC是一种体系结构模式:它描述了系统的主要部分、它们的职责以及它们如何交互。它没有强制实施任何具体措施。

例如,最初的MVC是由OOP先驱在Smalltalk上下文中于1979年设计的。在这种动态类型语言中,没有接口:对象与向其发送消息的其他对象进行通信,甚至不确定接收方是否能够处理消息。

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

不同的视图可能显示不同的内容。让我们假设这个模型是一辆汽车的数字孪生兄弟。一个视图可以只显示速度,就像它显示在仪表板上一样。另一个视图可以忽略速度,只在3D中绘制汽车。为了避免模型必须了解每种可能的视图的所有内部细节,广播保持极简主义。

观察员和通知

notify()消息就是这种典型的极简主义通信。

GoF推广了设计模式,并在他们的书开始时将MVC的不同特性分解为不同的独立模式。视图和模型之间的订阅/通知关系被映射到观察者模式。由于它们的设计非常适合强类型语言,notify()/update()变得非常流行。

模式如下:

  • 模型("主题")的非常不同的观察者("视图")都使用相同的接口来定义所有视图通用的方法。在GoF中,他们使用了一个抽象的Observer类。然而,在许多现代语言中,倾向于用interface代替抽象类
  • 观察者(视图)订阅/注册一个主题(模型),该主题跟踪所有注册的对象
  • 每当模型发生变化时,模型就会触发一个广播,通知所有观察者发生了变化(notify()/update()),而不确切地说明发生了什么

替代方案

接口就像一个空壳,里面隐藏着可能存在的东西。它们本身不足以确定一个全面的解决办法;它们只是谜题的一部分:

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

在这两种情况下,拥有接口可以让模型和视图相互理解。但是,为了实现MVC广播,模型需要知道向谁通知更改,视图也必须知道听取谁的意见

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

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

最新更新