程序员

我所理解的MVP模式

2018-06-24  本文已影响4人  默铭志

前几天看了一些关于MVP的一些文章,发展每个人都有自己的见解,并不能达到高度的统一,不过笔者还是大受裨益。今天笔者也谈谈自己对MVP的一些理解,供大家学习交流。

由于笔者是一枚iOS开发,所以接下来有些地方会结合iOS来,以期将笔者想说的都讲的清楚明白。

Demo地址:https://github.com/yuexygoodman/MVPExample

MVP与其说是设计模式,还不如说是一种程序架构范式,说明了我们应该怎样更好的组织整个项目的代码和资源。

MVP模块关系图

M:Model层,数据服务层,负责数据的增删改查。在服务端就包括mysql数据库操作、本地cache等;在客户端就包括调用服务器API、各种形式的数据缓存等。有些朋友将Model层理解为数据模型层,数据模型归根结底是数据,设计数据模型是为了在面向对象的程序设计中更好的表达数据。所以数据模型贯穿于整个应用程序,不应该将Model层单单理解为是数据模型。但Model层往往负责将接收到的数据转化为相应的数据模型供上层使用。

V:View层,视图界面层,负责UI的渲染、子视图的组织、UI事件、用户交互等。在有些网友看来,View层是比较轻的一层,大多数时候只需要调用系统的UI控件,绑定需要的UI事件就完事了,很多平台甚至拖拖控件就行。但是实际上是因为平台为我们做了大多数的事,我们不需要去考虑怎么有效的渲染界面,也不需要去考虑怎样去实现各种各样的交互事件(触摸),只需要关注应用本身就可以了。

P:Presenter层,有得朋友将其叫作发布者,百度翻译为主持人,笔者觉得后者更贴切些。 Presenter既是中间人,在ViewModel之间起到桥梁的作用,又是一个独立的大模块,封装了业务的复杂度,将UI和业务逻辑拆分开来,使UI和业务都可以独立的进行变化。从整体的数据流向上看,PresenterModel层获取数据,并通过接口发送给View层展示;View层将用户交互传递给Presenter,由Presenter完成相应的业务逻辑,这其中可能会有Model层的参与,比如Presenter调用Model层的接口来保存数据。

面向接口编程的MVP

在理想状态下,ModelViewPresenter这三层都应该是面向接口(interface/protocol)编程的,从而达到低耦合,高复用的效果。同时,由于业务不依赖于UI,使单元测试也更容易进行。很多人并没有单元测试的重要性,一个网友描述的挺好的,这里直接将原话贴出来:

单元测试可以大大地减少程序运行时才能发现的问题,这通常可以节省「用户反馈」->「Bug修复」->「新版本发布」->「用户安装新版本」这个耗时长达一周以上的过程。所以,程序的可测试性对于程序的稳定性是异常重要的。

上面都说了,完全面向接口编程是最理想的状态。实际情况则是过份的设计大大增加了开发过程中的复杂度,降低了开发的效率,最终可能影响项目的进度。所以在实际的项目开发中,对MVP的应用深度应该视情况而定:

笔者认为,实现MVP模式的最低原则是:

  1. ViewModel之间不能直接进行交互,必须通过Presenter来交流数据;
  2. 尽量的将业务逻辑和UI展示分开;
  3. 尽量使用面向接口的方式来实现MVP三层,特别是对于ViewPresenter之间的交互。
iOS平台上的MVP

在iOS平台上,目前大多数采用的MVC的实现,实际上已经符合了MVP的特点了,只是ViewController做了更多的事。ViewController充当了Presenter的角色,在ViewModel之间起到了桥梁的作用,同时封装了业务逻辑。除此之外,ViewController还负责界面的生命周期、视图组织、页面跳转等。ViewController虽然属于View层,但很多时候我们还是会用它来封装业务逻辑,由于承担了过多的职责,在有些复杂的情况下,ViewController往往变得不堪重负,给维护代码和新增功能都带来了不利影响。为了给ViewController瘦身,我们可以采取以下措施,供参考:

最后给出一个iOS平台上实现MVP模式的例子,供大家参考:
由于代码比较多,这里只贴出主要的接口代码,项目源码请查看https://github.com/yuexygoodman/MVPExample
1、登录界面,View层接口

@protocol ILoginView<NSObject>

- (void)setPresenter:(id<ILoginPresenter>)presenter;

- (void)loadWithLastAccount:(NSString *)account pwd:(NSString *)pwd;//显示历史账号

- (void)showLoginError:(NSString *)err;//显示登陆错误

- (void)showLoading;//显示正在登陆

- (void)hideLoading;//登陆完成后隐藏

- (void)navToMain;//切换界面到主界面

@end

2、登录界面 Presenter接口

@protocol ILoginPresenter<NSObject>

- (void)setLoginView:(id<ILoginView>)loginView;

- (void)start;

- (void)onLoginWithAccount:(NSString *)account pwd:(NSString *)pwd;//处理登录逻辑

@end

3、朋友管理界面 View层接口

@protocol IFriendView<NSObject>

- (void)setPresenter:(id<IFriendPresenter>)presenter;

- (void)loadWithFriends:(NSArray<Friend *> *)friends;//显示列表

- (void)confirmFriend:(Friend *)fri msg:(NSString *)msg;//向用户展示再次确认窗口

- (void)unShowingForFriend:(Friend *)fri;//取消被删除朋友的显示

- (void)showRemoveError:(NSString *)msg;//显示错误

4、朋友管理界面 Presenter接口

@protocol IFriendPresenter<NSObject>

- (void)setFriendView:(id<IFriendView>)friendView;

- (void)start;//启动

- (void)onRemoveFriend:(Friend *)fri;//删除业务

- (void)onSureRemoveFriend:(Friend *)fri;//直接删除

@end

再次给出Demo地址:https://github.com/yuexygoodman/MVPExample 欢迎大家访问
对于MVP模式的理解就到此为止了,下一篇笔者准备继续说一说MVVM,以上内容,均属笔者拙见。有什么不对的地方,烦请指教。

上一篇下一篇

猜你喜欢

热点阅读