理解并运用MVC,MVP,MVVM

前言

MVC,MVP,MVVM 属于 GUI 软件设计,它们都强调将软件的视图显示与业务逻辑进行分离,将软件拆分为三个部分,分别负责数据操作、视图逻辑、业务逻辑。

业务逻辑指的是任何与数据操作、视图操作的定义与实现无关的功能。
具体来说,业务逻辑中不应该出现如何操作视图或如何操作数据的细节。
对于这些操作,应该在视图层或数据层定义相关的功能,在这些功能内实现相关操作,再由业务逻辑去调用这些功能的 API。

这三个部分对程序有一个简单的划分:

  • Model 负责维护软件的数据,实现那些处理数据的功能,供外部调用,它保持独立,不依赖 View 与 Controller。
  • View 负责用户界面,将数据展示用户,实现那些操作视图的功能,供外部调用。
  • Conttoller/Presenter/ViewModel:
    负责实现软件的业务逻辑,协调 View 与 Model,将 Model 的数据展示到 View 的用户界面,并将 View 对数据的更改更新至 Model。

MVC

MVC 将软件按功能进行拆分,但是对各部分的职责、各部分的协作关系没有很明确的约束。

根据职责与关系的不同,MVC 也有不同的实现。

Passive View MVC

被动视图指得是 View 的用户界面被动的等待更新,它不依赖 Model 来操作数据,将 View 数据的初始化、更新以及对 Model 数据的更新交给 Controller。

这样的定义使得 Model 与 View 都是独立的,可被复用。

那 Model, View, Controller 具体该承担什么样的职责呢?

  • Model 的职责很明确,提供操作数据的功能。

  • Passive View 呢?是不是意味着着它只能定义如何操作视图,但不能自行操作呢?
    不然,对于那些只影响视图,不涉及 Model 数据操作的视图操作,应该由 View 自行处理,没有必要再委托 Controller 来调用。而那些与 Model 数据相关的视图操作,可以由 View 封装好供 Controller调用。比如获取数据要访问网络,属于耗时操作,过程中要展示进度条,那针对进度条的操作就应该封装为 API 以供外部调用

  • Controller 负责具体的业务逻辑。对于 View 中响应用户输入的功能,凡是涉及业务逻辑的,View 自己不实现,而是在 Controller 中实现,View 去调用。

View 可以持续响应用户的输入,如果将所有的业务逻辑都放在 Controller 中,会使得 Controller 任务繁重。
虽然可以通过将 Controller 拆分为多个子模块来解决这个问题,但是思考如何为各个子模块分配职责也是个麻烦事儿。另外, 对 Model 与 View 调用可能会分散在代码的许多地方,难以管理。

要解决 Controller 任务重的问题,可以将部分业务逻辑转移出去,比如 Model 与 View 之间的数据同步逻辑是可以放在 View 中。

要实现数据的同步,View 需要知道 Model 的数据变化,而 Model 因为不能依赖 View,也就不能去更新 View。要解决这个问题,可以使用观察者模式。

Observer Pattern

引入观察者模式,将 Model 定义为可观察对象,这样 View 就可以在 Model 数据更新后更新用户界面了。除了 View, Controller 也能向 Model 注册观察者,执行一些与用户界面无关的操作。

Active Model MVC / Active View MVC

View 可以主动的更新视图,Model 也可以将自身变化主动的通知观察者,应用观察者模式的 MVC 可以被称作 Active View MVC 或 Active Model MVC。

View 与 Model 之间的数据同步操作,可能是简单的,比如将数据原封不动地传递,或者进行数据拼接、类型转换;
也可能是复杂的,比如类似加解密这样的复杂计算,访问网络处理数据,调用第三方软行处理数据,之后再进行同步操作。

不可能将所有的数据同步逻辑都转移到 View 中,好的做法是将简单的同步操作放在 View 中实现,复杂的在 Controller 中实现。

WEB MVC

在服务器端 WEB 软件开发也有 MVC 的概念,但是 View 往往只是一个 HTML 文档, 不能响应用户输入,但浏览器根据 HTML 来渲染界面,倒是也符合 MVC 对 View 的定义。

MVP

MVP 就是 MVC,MVP 有两种实现定义:

  1. Passive View MVP: 就是 Passive View MVC
  2. Supervising Controller MVP: 就是 Active View MVC,是将简单的同步操作放在 View 中实现,复杂的在 Prennter 中实现

真要说有什么不同,可能就是 MVP 强制约定了 View 与 Model 的关系,而 MVC 对此并无限制。

在 OOP 项目实践中,View 被定义为接口,而 Presenter 被定义为类,View 被注入到 Presenter 中,这样可以保证 View 与 Presenter 能被一起复用。

MVC / MVP 代码示例

Android Java 伪代码:

interface IView {
  public void showPeogressbar();
  public void cancelPeogressbar();
}
class Presenter {
  private Iview view;
  void Presenter(IView v){
    this.view = v;
  }
  
  public void logic() {
    this.view.showPeogressbar();
    // dosth
    this.view.cancelPeogressbar();
  }
}

class MainActivity implements IView() {
  private Presenter presenter;
  public void onCreate() {
    this.presenter = new Presenter(this);
    findViewById(R.id.btn).setOnclickListente((View view)->{
      this.presenter.logic();
    });
  }
  
  public void showPeogressbar() {}
  public void cancelPeogressbar() {}
}

MVVM

MVC 和 MVP 本质上是一样的,而 Model-View-ViewModel(MVVM) 也是将软件分为三个部分,ViewModel 与 MVC 的 Controller 职责也是一样的,负责业务逻辑。MVP 并没有给MVC引入什么新的概念,但 MVVM 引入了新的概念:

  • 将视图从业务逻辑中分离
  • 视图状态
  • 数据驱动视图

视图的状态

  • 视图中会变化的数据
  • 视图用于响应用户输入的业务逻辑,即视图的行为

视图的状态的本质是给视图引入了一个代理,即 ViewModel,通过代理来间接操作视图。

分离视图与业务逻辑

将视图从业务逻辑中分离的核心是业务逻辑中不操作视图,只操作数据,在业务逻辑中不会去访问视图的细节。分离视图的方式是实现 数据驱动视图

数据驱动视图

数据驱动视图的直观表现是,改变数据,视图就更新。其原理是 ViewModel 维护一个数据集合,与 View 的状态一一对应。本质上还是观察者模式,View 通过观察 ViewModel 的数据变化,来更新视图。而 View 因用户输入产生的状态变化也会主动更新到 ViewModel 的数据集合中。

需要注意的是,ViewModel 名字里的 'Model' 指得是 View 的状态所对应的数据,而与 Model 无关,View 状态的更新不会同步到 Model 中。
更改 ViewModel 的数据以更新 View 状态,属于视图逻辑,而同步 View 状态对应的数据到 Model中是业务逻辑,我们还要自行实现。

声明式 UI

视图的数据和行为的绑定操作不会凭空就能从业务逻辑中分离,我们肯定要写代码来实现,但是也不可能每个 View 都先编写一个 ViewModel,那样会有太多的样板代码。

既然写代码麻烦,那就生成代码。使用特定的文本格式,或者说标记语言来声明视图,在声明中为视图绑定 ViewModel,为控件绑定状态(数据和行为),然后写一个解析器来生成代码。

不同的开发平台有不同的实现,比如 Javascript Web 应用使用 HTML 或者 JSX 声明视图,Android 使用 XML 或 Compose 来说明视图,而微软的 WPF .NET 使用 xaml, Blazor 使用 razor。

使用标记语言来定义视图,真正做到了将视图的关注点从业务逻辑中分离,因为解析器只用编写一次,算不得业务逻辑。

一切皆数据

数据驱动视图的开发方式已经是所有追求先进性的 GUI 软件开发框架所必备的了。

在 ViewModel 中是没有 View 的细节的,只有 View 的状态所对应的数据。开发业务逻辑的过程中可以完全当视图不存在,一切都是数据。

热门相关:赤子心浪子情   黑帮暴徒   辛巴达与牛头怪   今天妈妈,明天姐姐   魔镜奇缘