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,忽略不相关的变化事件,处理剩下的。
在经典的 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,忽略不相关的变化事件,处理剩下的。