关于MVC的争论

关于MVC的争论已经有非常多,对此我的观点是:对于iOS开发中的绝大部分场景来说,MVC本身是没有问题的,你觉得的MVC的问题,一定是你自己理解的问题(资深架构师请自己主动忽略本文).

行文过程中查阅了互联网上的大量文档,当中水平良莠不齐(最常见的就是MVC改个名就当MVVM的),当然也有很多很有价值的參考资料,在文末会逐一列举,以供參考.

iOS中的MVC和MVP

Cocoa版本号的MVC

依据官网上的描写叙述, Cocoa中的MVC是这种:

  • Model Objects Encapsulate Data and Basic Behaviors

  • View Objects Present Information to the User

  • Controller Objects Tie the Model to the View

C和P的区别

通过搜索引擎,发现事实上MVP事实上两种的:

  1. Passive View

  2. Supervising Controller

网上绝对部分谈论MVP的文章谈论的事实上都是Passive View,这里放上一张Passive View的示意图:

乍一看上去是不是和MVC一样?我也一直一头雾水,直到在stackoverflow看到这个答案:


MVP: the view is in charge. The view, in most cases, creates its presenter. The presenter will interact with the model and manipulate the view through an interface. The view will sometimes interact with the presenter, usually through some interface.
This comes down to implementation; do you want the view to call methods on the presenter or do you want the view to have events the presenter listens to?

It boils down to this: The view knows about the presenter. The view delegates to the presenter.


MVC: the controller is in charge. The controller is created or accessed based on some event/request. The controller then creates the appropriate view and interacts with the model to further configure the view. It boils down to: the controller creates
and manages the view; the view is slave to the controller. The view does not know about the controller.


简而言之,MVP是View驱动的,View层持有一个相应Presenter的引用,View上的交互事件首先会调用Presenter提供的接口,然后Presenter调用Model提供的方法取得数据,最后Presenter将取得的数据传递到View上展示.

MVC则是由Controller驱动的,Controller持有View,并响应View上的交互事件,依据交互调用不同的Model方法取得反馈数据,再将数据传递给View展示.

我的理解是,MVP是用户视角:所见即View.MVC则是程序猿视角:I control everyone.

理解MVC和MVP的区别困惑的地方在于,UIViewController究竟是属于C(P)层还是V层呢?以下将分别详细分析一下这两种观点.

观点一:UIViewController的归属--->View

假设把UIViewController视为V层,即上面MVP示意图中的Passive View,那么UIViewController将仅仅负责View布局相关逻辑,不涉及不论什么与Model层的交互!!

不涉及不论什么与Model层的交互!!

不涉及不论什么与Model层的交互!!

全部的业务逻辑交互通过UIViewController持有的Presenter与Model间的调用来完毕.

观点二:UIViewController的归属--->Controller

那假设把UIViewController视为C层,从MVC设计理念上来说,C层不会负责详细View的布局及展示逻辑,可是因为iOS中UIViewController的特殊设计,导致非常多开发人员直接就在UIViewController包括了非常多详细布局相关的代码,更可怕的情况是不止是View的初始化,包括网络请求及详细业务处理也被包括到UIViewController中,这或许就是有人戏称MVC为:MassiveViewController的原因.

Model,DataInfo以及对胖瘦Model的争议

Model和DataInfo的差异

MVC架构思想中更倾向于Model是一个Layer,而不是一个Object(Java或Android中的bean).

所以这里的DataInfo我将其定义为一个DTO(Data Transfer Objec),更简单的来说,就是一个数据结构,跟我们在学校学习C语言时写的一个student结构体基本是一个意思.

我的理解是,Model是用来处理业务逻辑的,可视为传统开发三层架构中的BLL(Bussiness Logic Layer)和DAL(Data Access Layer)的合体,负责全部的详细业务.比方,对一个包括安全认证的App,你可能须要一个AuthModel来负责全部的认证逻辑以及认证信息的本地持久化.这样,Controller中仅仅须要调用AuthModel提供的接口便能完毕对应安全认证功能,职责分明.

Model中的一些方法的产出DTO,用来更新View.比如UserModel会去查询用户信息,然后将server返回的用户信息转换成一个本地的UserInfo,将这个UserInfo传递给View进行展示.

因此业界关于胖瘦Model的争议,我很多其它的理解是对于DataInfo是否须要提供涉及到业务的扩展功能的争议.

业务场景举例

举例一个业务场景,一个用户信息View上须要展示用户性别,一般来说server仅仅会在返回的用户信息中包括一个sex字段(这里用0代表女性,1代表男性),须要使用的时候可能须要使用if语句进行推断然后输出不同的性别文字或图片.

从个人习惯上来说,非常多开发人员会将server返回的用户信息转换成一个本地的UserInfo DTO,然后将这个DTO传递给要相应须要展示的View,然后在View中进行输出推断.

当然,开发人员可能会使用如今非常流行的一些字典转模型框架(YYModel,MJextension等),也能够使用这些框架提供的配置接口在转换时就实现这样的输出逻辑的转换,或者直接在UerInfo sex属性的getter方法中进行转换后输出.

无论如何,仅仅要在DataInfo这个层级上做了类似的这些转换,那么业务逻辑就已经侵入了DTO的定义.

一种解决思路

可是,这样的场景差点儿又是不可避免的,怎样解决呢?被误解的 MVC 和被神化的 MVVM提出了一种借鉴MVVM的解决思路,详细做法就是将 ViewController 给 View 传递数据这个过程,抽象成构造 ViewModel 的过程.这样抽象之后。View 仅仅接受 ViewModel,而 Controller
仅仅须要传递 ViewModel 这么一行代码。而另外构造 ViewModel 的过程,我们就能够移动到另外的类中了.

在我看来,这样ViewModel层事实上仅仅是把上文中对DataInfo的扩展单独提炼了出来.这样就将View层全然与业务逻辑全然隔离开.

本次基于MVC的项目重构步骤

思考要解决的问题

回到项目重构的问题上来,我觉得项目重构首先要想清楚的问题:

  1. 项目层级怎样划分?

  2. 大的业务场景有哪些?

  3. 将UIViewController归类为View还是Controller?

  4. 谁来负责网络请求,Model还是Controller?

  5. 从Model中取得数据后Controller怎么把数据传递给View去展示?

    依照View层级逐级传递?是否须要使用ViewModel?

  6. Model的生命周期怎么控制?

    (全局Model和私有Model的划分)

  7. View层级结构越来越深时,怎么传递用户的交互操作?

    (毫无疑问NSNotification)

UIViewController的划分

本次重构中还是将UIViewController归类为C层,可是为了将UIViewController彻底和UIView分离开,命名上我们直接使用XXXController,我们对每个XXXController设计了一个相应的名为的XXXContainerView的UIView对象,全部的view布局都会在这个XXXContainerView中完毕.

项目文件夹结构

重构后的项目文件夹结构例如以下:

一级文件夹  子文件夹  文件夹说明 
Macro    存放开发过程中所需的一些宏定义 
Category    存放不涉及业务,用来辅助开发的分类 
Tools  不同的业务工具类  存放涉及轻量级业务的处理类,比方依据不同业务格式化输出不同的字符串 
Views  不同的业务模块页面名  存放不同业务模块页面下的V 
Controllers  不同的业务模块页面名  存放不同业务模块页面下的C 
ViewModels  不同数据模块名  数据翻译层,将DataInfo数据翻译为View可直接展示的数据,但本次重构中因为时间因素不强制使用 
Model  PublicModel  公用的全局Model,比方用户信息UserModel 
  MoudleModel  单独某个模块使用的私有Model,仅仅负责私有业务 
Services  不同的Service  提供底层服务,比如HttpService,SecurityService 

业务场景划分

因为之前赶进度开发,没有做详细的功能拆分.本次重构之前使用了StartUML绘制了主要场景下的UML图,包含类图,时序图,流程图.

强烈推荐新项目正式编码之前就完毕这一步,并由前后端技术负责人主持进行UML评审.全部涉及到的业务Model的property以及public方法,全部DataInfo类的属性,甚至全部的Controller都会在绘制UML的过程中产出.当然,要想绘制全部场景下的UML图可能耗时比較久,一般来说仅仅要绘制出主要交互场景就可以.

网络请求

在手机端基本上全部的网络请求都是跟业务挂钩的,显然放在Model里更合适.至于请求完毕后的回调就看个人习惯了,delegate或者block都是可行的.

兴许

因为时间原因,并没有写出详细的演示样例代码,之后会针对一个演示样例场景,写出我理解中的各个MV(X)模式的參考代码,期待成文后与同行探讨.

MVVM扩展

放一张MVVM的示意图:

看上去是不是非常像MVP?仅仅是多了View和ViewModel的双向绑定,这里强调一点,RAC不一定登陆MVVM,MVVM也不一定要使用RAC.

參考资料

iOS 基于 MVC 的项目重构总结的更多相关文章

  1. iOS基于MVC的项目重构总结

    关于MVC的争论 关于MVC的争论已经有很多,对此我的观点是:对于iOS开发中的绝大部分场景来说,MVC本身是没有问题的,你认为的MVC的问题,一定是你自己理解的问题(资深架构师请自动忽略本文). 行 ...

  2. 转:iOS基于MVC的项目重构总结

    转:http://www.cocoachina.com/ios/20160519/16346.html 关于MVC的争论 关于MVC的争论已经有很多,对此我的观点是:对于iOS开发中的绝大部分场景来说 ...

  3. iOS 基于MVC设计模式的基类设计

    iOS 基于MVC设计模式的基类设计 https://www.jianshu.com/p/3b580ffdae00

  4. PHP项目感悟 -- 从CI框架来看iOS的MVC

    其实这几天一直都想找时间把这个感悟整理出来,也是这一段一直思考的问题,因为这一段参加一个PHP后台项目的开发,框架使用的是CI,随着项目的进展,对于CI接触的也越多,但是由于理解的可能并不深刻,我也只 ...

  5. [转]Asp.Net大型项目实践(11)-基于MVC Action粒度的权限管理【续】【源码在这里】(在线demo,全部源码)

    本文转自:http://www.cnblogs.com/legendxian/archive/2010/01/25/1655551.html 接上篇Asp.Net大型项目实践(10)-基于MVC Ac ...

  6. struts1:(Struts重构)构建一个简单的基于MVC模式的JavaWeb

    在构建一个简单的基于MVC模式的JavaWeb 中,我们使用了JSP+Servlet+JavaBean构建了一个基于MVC模式的简单登录系统,但在其小结中已经指出,这种模式下的Controller 和 ...

  7. 零基础搭建 spring mvc 4 项目(本文基于 Servlet 3.0)

    作者各必备工具的版本如下: Tomcat:apache-tomcat-7.0.63 (下载链接) Java EE - Eclipse:Luna Service Release 1 v4.4.1 (下载 ...

  8. iOS、mac开源项目及库汇总

    原文地址:http://blog.csdn.net/qq_26359763/article/details/51076499    iOS每日一记------------之 中级完美大整理 iOS.m ...

  9. iOS 关于MVC和MVVM设计模式的那些事

    一.概述 在 iOS 开发中,MVC(Model View Controller)是构建iOS App的标准模式,是苹果推荐的一个用来组织代码的权威范式.Apple甚至是这么说的.在MVC下,所有的对 ...

随机推荐

  1. Python+Selenium 自动化测试获取测试报告内容并发送邮件

    这里封装一个send_mail()方法,用于测试完成后读取测试报告内容,并将测试结果通过邮件发送到接收人 # coding: utf-8 import smtplib from email.mime. ...

  2. webgl 的空间变换(下):空间变换

    在网上看了很多关于在三维世界中怎么把一个顶点经过一步步变化,最终呈现在我们的屏幕上的. 其实很多博客或者书籍已经讲的很清楚了,那为什么我还要特别再写一次博客来阐述自己观点呢?(这里只针对那些学习web ...

  3. 用npm来部署快速一个httpweb服务器

    https://blog.csdn.net/u012182627/article/details/55060594 http-server的安装######注意事项 安装http-server的时候 ...

  4. win7 命令行禁用开启usb存储

    禁用: reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\usbstor" /v Start /t reg ...

  5. JavaSE-21 字符编码简介

    ASCII ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英 ...

  6. 【牛客小白月赛6】 C 桃花 - 树上最长路

    题目地址:https://www.nowcoder.com/acm/contest/136/C dfs找出最长路和次长路,将两个结果相加再加上起点即可: #include<iostream> ...

  7. <Redis> 入门四 Jedis操作Redis

    pom依赖 <dependencies> <!-- https://mvnrepository.com/artifact/redis.clients/jedis --> < ...

  8. crm项目之stark组件前戏(二)

    stark组件的设计主要来源于django中admin的功能,在django admin中只需要将模型表进行注册,就可以在页面对该表进行curd的动作,那么django admin是如何做的呢? 在d ...

  9. Matlab学习笔记(二)

    二.MATLAB基础知识 (二)数值.变量和表达式 命名规则: 变量名对大小写敏感,即区分大小写 变量名必须以字母开头,后面可以采用数字.下划线和字母,但不能使用空格.标点符号和运算符 变量名最长可以 ...

  10. Xcode8、 iOS10 适配问题

    调用相机.相册.麦克风.位置等隐私问题崩溃解决办法 你的项目中访问了隐私数据,比如:相机,相册,联系人等,在Xcode8中打开编译的话,统统会crash,控制台会输出下面这样的日志: 这是因为iOS对 ...