MVP模式是你的救命稻草吗?

简介:

为什么要学习架构?

不管是MVC还是MVP,亦或则其他架构,它们的设计目的都是为了达到编码的最高境界,那就是:低藕合,高复用,易测试,好维护。

而要达到这个终极目标,首先要理解的是每个部分各自负责些什么,以及如何组合在一起。因此我个人认为,学习架构关键在两步:

  1. 如何把缠在一起的代码拆分
  2. 如何把拆开的代码再组合

很多新手在刚做项目时,都会把所有的代码,如数据的访问和处理,数据的展示,用户的输入都写在一起,代码和思维都呈现出一种线性的形式,一切都是直来直往的。这样代码量确实少,写的时候也觉得方便,但是带来了几个致命的问题:

  1. 当业务越来越复杂时,修改代码成了噩梦。同样的逻辑放在不同的地方,本来只用改一处的变成了需要改几百处。而又因为所有的逻辑都互相牵扯住,导致本来只想改一处的,结果却影响了几百处。
  2. 当时间越来越遥远时,理解代码成了噩梦。本来只需要阅读几行的时候,却因为所有的代码都杂在一起变成了要阅读几千行。时间一长,重新阅读时,别说别人,就是自己也很难一下就能掌握关键点。
  3. 当需要做一个功能时,却发现代码无法复用,明明是一样的逻辑也只能靠Ctrl+CCtrl+V。这又为今后修改代码时增加了工作量。
  4. 当需要测试时确发现很难进行测试,每次修改一处代码后都必须进行重复的人工测试,无法进行自动化测试,模块和模块也无法拆开来进行独立的单元测试,每次都要整体的测一遍才能确保一切完好如初。

要换的不是架构,而是思维方式

其实目前市面上的架构模式已经有很多种,各有不同,但模式终究只是一种设计理念的表现形式,学习再多的架构,你也只是多会用了几种工具而已,学习一种模式其实是在学一种思维方式:

如何在解决问题的时候把问题合理的拆分,又如何将拆分的零件合理的组装成解决问题的工具。

将这种思维方式深入到你的大脑里,血液里,直至骨髓,让它成为你思考问题的一种习惯和定式,逐渐成为你的一部分,那么这时你已达到无招胜有招的境界了。

闲话先不扯了,回正题。

实现架构没有唯一标准

这里首先需要说明的是无论MVP或MVC还是MVVM等任何一种架构和模式其实都没有谁优谁劣之分,而且就算是同一种架构,也可以根据不同的使用场景来做不同的实现方式,这里并没有宇宙绝对的对错标准和概念定义。这和张三丰在教无忌太极拳以后让其先忘掉招式是一样的道理,在应用型领域,定式和概念只应是在学习的过程中才存在的,而真正学会以后应该马上忘掉定式,忘掉概念,将其用熟用活才是关键。

所以说我在此描述的概念也不是唯一的标准,而只是个人对其的理解。

什么是MVC

因为MVP是MVC的一个变种,因此我们先来看在MVC里代码是如何拆分和组合的,这里简要的描述常见的定义:

  1. 拆分:Model负责数据,View负责显示,Controller负责用户输入。
  2. 组合:View将用户操作和事件传递给Controller,Controller将用户命令翻译成消息来传递给Model,Model在处理完数据后,通知View来显示给用户,而View又从Model取出数据。

我认为在学习MVP之前,必须深刻理解什么叫做MVC,因为两者的区别其实没有你想象中的那么大,与其神话并盲目追崇新的架构,期望其能解脱你于苦海,还不如深刻的理解MVC的设计理念,这就和学习一门新语言一样,只有你真正深刻的理解了其思维方式,那么学习新的一门语言其实都是易如反掌的。因为它们其实都是在做一件事,只是做的过程上有些许差异而已。

更多MVC的理解,可以参考我之前写的一篇文章:在谈MVP之前,你真的懂MVC吗?

什么是MVP

MVP与MVC最大的区别就在与将Model和View通过Presenter隔开了,不再允许其互相直接通信,而所有的消息都是通过Presenter这个中间人来传递。

而这样做的目的主要是为了将数据和展示划出更明确的界限。

首先我们来看MVP到底是在解决什么问题的:

  • 数据管理
    1. 什么是数据?(Model)
    2. 如何筛选数据?(Selections)
    3. 如何改变数据?(Commands)
  • 用户界面
    1. 如何展示数据?(View)
    2. 如何通过事件来改变数据?(Interactor)
    3. 如何将这些放在一起?(Presenter)

可以看出其实一个GUI程序的核心,还是在于用户和数据之间的关系。而架构的引入也是为了解决这几个核心的问题。

那么MVP又是如何解决这几个问题的,Model,View,Presenter三者又各自负责什么呢?谁来负责请求网络数据,访问和存储本地数据,谁来负责处理数据,谁来负责显示数据,谁又来负责和用户交互呢?

具体表现在代码上,也可以说:网络请求应该放在哪,数据库访问应该放在哪,业务逻辑应该放在哪里,处理用户输入应该放在哪,谁又来控制显示或隐藏View的等具体的细节问题。

带着这些具体问题,我们一起来学习。

如何拆分

首先来看MVP各自负责什么:

  1. Model,负责定义数据(解决什么是数据)
  2. Presenter, 负责在Model和View之间,从model里取出数据,格式化后在View上展示(解决如何把数据和用户界面放在一起)。
  3. View,负责担任一个被动界面,用于展示数据。(解决如何展示数据)

和MVC比较而已,这里出现一个最大的疑问就是:那么谁来负责和用户的操作交互呢?答案是,用户在View上的所有操作(事件)都由View路由给Presenter,由Presenter来与其交互。

而和MVC最大的区别在于Model和View完全被Presenter隔开了,Presenter作为它们之间的中间人去传递所有数据。

如何组合

三者又是如何组合起来的呢?

很显然Presenter作为中间者,它是同时拥有View和Model的引用的,为了在它们之间起到桥梁作用,即Presenter会主动和View和Model进行通信

Model和View必须是完全隔离的,不允许两者之间互相通信,保持对彼此的不感知,这样的好处是你彻底将数据和展示分离来开,并且可以独立的为Model去做测试。

Model在三者中是独立性最高的,Model不应该拥有对View的引用,而且Model也不需要保存对Presenter的引用,对于Presenter而已,Model只需要提供接口,等着Presenter来调用时返回相应数据即可,这和经典MVC模式中是非常不同的,在MVC中Model在数据发送变化后,是需要发送广播来告之View去更新用户界面的,而在MVP中,Model是不应该去通知View,而是通知Presenter来间接的更新View的。

Presenter和Model的关系也应该是基于接口来通信,这样才能把Model和Presenter的耦合度也降到最低,那么在需要改变Model内部实现,甚至彻底替换Model的时候,Presenter则是无需随之改变的。这样做带来的另一个好处就是你可以通过Mock一个Model来对Presenter以及View做模拟测试了,从而提高了可测试性。

那么View和Presenter的关系呢?View是需要拥有对Presenter的引用,但仅仅是为了将用户的操作和事件立即传递给Presenter,为了让View和Presenter耦合较低,View也只应该通过接口与Presenter通信,从而保证View是完全被动的,一方面它由用户的操作触发来和Presenter通信,另一方面它完全受Presenter控制,唯一需要做的事情就是如何展示数据。

简要总结三者之间的关系是:View和Model之间没有联系,View通过接口向Presenter来传递用户操作,Model不主动和Presenter联系,被动的等着Presenter来调用其接口,Presenter通过接口和View/Model来联系。

View <- 接口 <- Presenter ->接口 -> Model

View -> 接口 -> Presenter <- 接口 <- Model

Talk is cheap, show me the code

为了便于理解,这里提供一些伪代码加注释演示一下如何实现MVP模式:

View

interface IUserView {

  void setPresenter(presenter); void showUsers(users); void showDeleteUserComplete(); void showDeleteUserError(); } class UserView implements IUserView { UserPresenter presenter; // 保持对Presenter的引用,用于路由用户操作 void setPresenter(presenter) { this.presenter = presenter; } // 将Presenter传递来的数据展示出来 void showUsers(users) { draw(users); } // Model操作数据成功后,通过Presenter来告之View需要更新用户界面 void showDeleteUserComplete() { alert("Delete User Complete"); } // Model操作数据失败后,也是通过Presenter来告之View需要更新用户界面 void showDeleteUserError() { alert("Delete User Fail"); } // 当用户点击某个按钮时,将用户操作路由给presenter,由presenter去处理 void onDeleteButtonClicked(event) { presenter.deleteUser(event); } }

Model

interface IUserModel {

  List<User> getUsers(); boolean deleteUserById(); } class UserModel implements IUserModel { // 在数据库里查找数据,并将数据返回给presenter List<User> getUsers() { return getUsersInDatabase(id); } // 在数据库里删除数据,并将结果返回给presenter User deleteUserById(id) { return deleteUserByIdInDatabase(id); } }

Presenter

interface IUserUserPresenter {

  void deleteUser(event); } class UserUserPresenter implements IUserPresenter { // 保持对View的引用 IUserView view; // 保持对Model的引用 IUserModel model; UserUserPresenter(IUserView view, IUserModel model) { this.view = view; this.model = model; this.view.setPresenter(this); } void start() { // 从Model中取出数据 List<User> users = model.getUsers(); // 将数据发送给View,让其展示到用户界面 view.showUsers(users); } void deleteUser(event) { // View将用户操作路由过来,由Presenter来处理 long uid = whichUserNeedToDeleteBy(event); // 将用户操作翻译成命令或消息传递给model,以改变数据 boolean success = model.deleteUserById(uid); // 将Model操作数据后的结果通知View来改变用户界面 if (success) { view.onDeleteUserSuccess(); } else { view.onDeleteUserFail(); } } }

OK,到此一个最简单的MVP模式就实现了,可以看到整个架构的轮廓已经很清晰了,而且面向接口编程也带来了很多的好处,让代码之间藕和较少,对测试支持也更为友好,理解和维护起来也更加方便了。

以后有时间再为大家描述如何在android里面实现MVP模式,以便更具体的理解。有疑问欢迎参与讨论,大家一起学习进步。

参考文档

  1. Model–view–presenter WIKI
  2. MVP: Model-View-PresenterThe Taligent Programming Model for C++ and Java

    本文转自 一点点征服   博客园博客,原文链接:http://www.cnblogs.com/ldq2016/p/6694415.html ,如需转载请自行联系原作者


相关文章
|
11月前
|
安全 前端开发 网络协议
MVP 架构最终审判 —— MVP 解决了哪些痛点,又引入了哪些坑?(三)
MVP 架构最终审判 —— MVP 解决了哪些痛点,又引入了哪些坑?(三)
100 0
|
11月前
|
存储 缓存 前端开发
MVP 架构最终审判 —— MVP 解决了哪些痛点,又引入了哪些坑?(二)
MVP 架构最终审判 —— MVP 解决了哪些痛点,又引入了哪些坑?(二)
81 0
|
11月前
|
设计模式 网络协议 前端开发
MVP 架构最终审判 —— MVP 解决了哪些痛点,又引入了哪些坑?(一)
MVP 架构最终审判 —— MVP 解决了哪些痛点,又引入了哪些坑?(一)
64 0
|
11月前
|
存储 前端开发 网络协议
“无架构”和“MVP”都救不了业务代码,MVVM能力挽狂澜?(二)
“无架构”和“MVP”都救不了业务代码,MVVM能力挽狂澜?(二)
86 0
|
11月前
|
存储 缓存 前端开发
“无架构”和“MVP”都救不了业务代码,MVVM能力挽狂澜?(二)(下)
“无架构”和“MVP”都救不了业务代码,MVVM能力挽狂澜?(二)
78 0
|
11月前
|
存储 缓存 前端开发
“无架构”和“MVP”都救不了业务代码,MVVM能力挽狂澜?(一)
“无架构”和“MVP”都救不了业务代码,MVVM能力挽狂澜?(一)
73 0
互联网创业模式
互联网创业模式
103 0
|
架构师
跨越技术和管理的鸿沟,打造一支有战斗力的团队——阿里云 MVP孙玄
阿里云MVP、奈学教育CEO孙玄对技术与架构管理本质的分享,具体分三个部分阐述 1.技术哲学本质 2.技术管理哲学本质 3.技术管理案例剖析 具体案例中的构建
3871 0
跨越技术和管理的鸿沟,打造一支有战斗力的团队——阿里云 MVP孙玄
|
TensorFlow 算法框架/工具 决策智能
可能是最懂架构的投资人——对话阿里云 MVP戚俊
戚俊的快速成长离不开恰逢其时的机遇和委以重任的伯乐,毕业一两年受邀创业。当腻了CTO,于是转行VC,作为大老板的副手再次起飞。这位90后技术人的故事,或许能给你新的启迪。
可能是最懂架构的投资人——对话阿里云 MVP戚俊
|
架构师 程序员 项目管理
“玄姐”,特立独行的架构师——对话阿里云 MVP孙玄
曾任58集团技术委员会主席、转转首席架构师的孙玄,一头飘逸长发,江湖人称“玄姐”。在职场风生水起时毅然辞去数百万年薪职位、放弃数千万期权。跟他聊过,我才直观体会到,原来梦想能有如此巨大的力量。
“玄姐”,特立独行的架构师——对话阿里云 MVP孙玄

热门文章

最新文章