阅读 104

白话 MVC、MVP、MVVP

白话 MVC、MVP、MVVP

注意这里单纯的通过例子来讲解 MVC MVP MVVP 这三种架构模式的起源和作用,不牵扯某种特定的语言。具体到各种语言各种软件系统上体现有所不同,但是原理都是这样的。清楚原理最重要

声明

假设要开发一款软缘分指数软件,软件如下图:

输入男生姓名和女生姓名后,点击按钮即可计算出缘分指数,就是这么一个软件。当然本身这个软件非常简单,但是为了更好的演示,不可能真的举出一个大项目的例子,由于这个软件本身过于简单,真正设计架构的话反而显得很鸡肋,因此你要想象成这个软件十分复杂!不然容易产生这么设计架构有什么用的想法。

起始阶段

最初阶段,程序员小明写这个软件的时候什么都没有想,直接上手码代码了,结果用于展示页面的代码,用于获取用户输入内容的代码,拿到用户输入的内容来计算缘分指数的代码,等等代码业务全部写在了一个文件中。完成了本软件的开发。

结果过了一段时间小明离职了,小华来接手他的代码,小华看到这个代码的时候,默默的留下了眼泪,一个文件中足足有 1 万多行代码,各种功能的代码彼此混合在一起,完全是大杂烩,想要修改一个地方根本不敢动。于是小华决定自己重新来写,因为这个大杂烩已经不可能维护了,改动比重写代价还要大!

MVC

小华是这样给这个程序分类的:

  • 首先是页面,页面可以单独抽离出来
  • 一些和页面判断有关的逻辑,比如:如果什么也没有填写的话,点击按钮是不会进行业务计算的。获取用户输入后去调用具体的业务逻辑的操作
  • 具体的计算缘分指数的的业务(需要查询大量数据得出)

页面部分用 V 来代表,只负责与页面有关的操作,比如按钮的摆放位置,计算出结果后页面的变化更新等等与页面有关的操作。

控制页面上的逻辑和调用具体业务逻辑的操作用 C 来代表,在 C 中只负责接收 V 的指令,然后调用业务逻辑,和操作 V

计算具体的与数据有关的业务逻辑用 M 来表示。

小华就按照这种方式来进行书写代码,这样写出来的代码可读性非常高,各层之间互相分离,不再是大杂烩了。而且分工也容易,写页面的写页面,写业务逻辑的写业务逻辑等等。

上面这样设计的流程图是这样的:

当然,你在网上可以还看到过其他的设计图,各种各样的都有,其实这个就看作者是怎么想的了,这个没有标准答案。主要的思想就是分层了,不再大杂烩了,至于它们之间的相互关系,就看你具体代码的体现了。

其实 MVC 在真正大型运用的时候,最接近这种

也就是说如果不触及复杂逻辑或者数据的情况下,一些简单逻辑就直接在 Controller 处理了,然后 Controller 再作用于 View 。还有一点就是 MVC 中 View 是可以和 Model 直接进行交流的。

当然如果你非要切断 Model 和 View 之间的关系的话,那样就演变成 MVP 了。

这就是 MVC 的雏形

M 表示 Model 专门用来做一些和数据(联网数据、本地数据、复杂逻辑)有关的逻辑

V 表示 View 专门用来控制页面的

C 表示 Controller 获取用户的输入,操作 M 和 V,说白了就是调用 M 和 V 中的方法

MVP

又过了一段时间,小华发现这种架构方式虽然比之前的大杂烩好很多,但是 M V C 之间相互依赖过多,由于 View 可以和 Model 直接通信,这就造成了 View 既依赖于 Controller 又依赖于 Model 。Controller 同样依赖于 View 和 Model。耦合性还是太高,于是进行了进一步的优化处理。让 M 和 V 彻底断了联系,只通过 P 来进行通信。

来自网络

这样 P 操作 Model,在 Model 中进行业务计算后得出结果,让Presenter 再去更新 View。

public void updateView(){
    view.setText("xxxxxx");
}
复制代码

这样Presenter 对 View 有依赖,这样 Presenter 就没法进行单独做单元测试了,必须等页面好了以后才可以(不然没法调用页面里面的方法)。于是进一步优化,让 View 层提出接口,Presenter 只依赖这个接口(接口很好写),这样页面还有完成也可以进行测试了。

来自网络

通过接口也降低了耦合性,其他的页面也可以实现这个接口。

MVVM

MVP 使用一段时间后,发现让 Presenter 调用 View 的方法去设置界面,仍然需要大量的、烦人的代码。

于是提出:能不能告诉 View 一个数据结构,然后 View 就能根据这个数据结构变化而自动随之变化呢?

于是有了一个叫 ViewModel 的东西,它可以和 View 层绑定。ViewModel 的变化,View 立刻就会变化。

那么什么是 ViewModel 呢?继续拿上面那个例子举例,ViewModel 差不多是这样的:

public class SalaryViewModel{
    String sex; // 性别,和 View 中的相关字段对应
    String index; // 姻缘指数,和 View 中的相关字段对应
  
    //.....
}
复制代码

当用户在界面上点击「计算」按钮的时候,只需要对 ViewModel 做出改变就行了。View 会根据 ViewModel 的变化做出更新,不用手工去设置。

ViewModel 和 View 的绑定问题,需要开发一个框架让两者绑定起来,微软的 WPF 和 Silverlight,Android 等框架和系统都可以实现 View 和 ViewModel 之间的映射和绑定。

到此整个架构的设计就非常合理了,代码维护起来也比较容易,可阅读行比较高!

总结

再次强调上面讲的都是 MVC MVP MVVP 大的设计思路,具体到不同的语言程序体现起来是不同的,没有准确的定义,具体的书写方式要根据开发者自己的思想来定义。目的就是让代码不同功能间相互独立,可阅读性强,便于扩充和重复利用。

一切不结合项目和实际问题空谈架构的行为都是耍流氓

切记不能为了架构而架构,项目较小的情况下,硬搬乱套架构只会增加你的代码量,导致非常冗余,这种情况下还不如好好提炼几个方法更容易查看维护。

起初写的代码全部混合在一起非常冗余不便于维护(当然如果说你写的时候做了某种抽离和分层,那么这就是你的一种架构思想),为了解决这个问题提出了 MVC 的架构模式,极大的解决了混为一滩的情况,但是这种思想设计之初 M 和 V 之间是可以相互通信的,导致了依赖关系太多,就出现了 MVP,MVP 出现后解决了 M 和 V 之间通信的情况,让 M 和 V 彻底失去关系,由 P 来通知 V 进行修改,再后来每次 P 还要通知 V 进行修改太麻烦就想法当 M 中的数据发生变化的时候直接修改 V 中的视图通过 ViewModle 来实现,这个时候就出现了 MVVM。

下面一篇文章来讲解这几种模式在 Android 开发中的具体体现。