MVVM后,下一代开发模式在哪?
凌云时刻
写在前面
讨论下一代开发模式的演化、优化方向和可能,不一定正确希望和感兴趣的读者交流。
任何模式的选择一定要根据当时的开发需要来决定。比如:实验性、迭代很快的简单需求,一般会先选择MVC尝试,待明确方向后,再考虑改为MVVM。
背景
首先,看下iOS首推的MVC模式。
M:单纯的从网络获取回来的数据模型
V:视图界面
C:ViewController
ViewController负责View和Model之间调度,View发生交互事件会通过target-action或者delegate方式回调给ViewController,与此同时ViewController还要承担把Model通过KVO、Notification方式传来的数据传输给View用于展示的责任。
随着业务越来越复杂,视图交互越复杂,导致Controller越来越臃肿,负重前行。福报修多了的结果就是,不行了就重构,重构不了就换掉。
为了解决MVC带来的问题,MVVM出现了。
把View和Controller都放在了View层(相当于把Controller一部分逻辑抽离了出来),Model层依然是服务端返回的数据模型。而ViewModel充当了一个UI适配器的角色,也就是说View中每个UI元素都应该在ViewModel找到与之对应的属性。除此之外,从Controller抽离出来的与UI有关的逻辑都放在了ViewModel中,这样就减轻了Controller的负担。
从以上的架构图中,我们可以很清晰的梳理出各自的分工。
View层:视图展示。包含UIView以及UIViewController,View层是可以持有ViewModel的。
ViewModel层:视图适配器。暴露属性与View元素显示内容或者元素状态一一对应。一般情况下ViewModel暴露的属性建议是readOnly的,还有一点,ViewModel层是可以持有Model的。
Model层:数据模型与持久化抽象模型。数据模型很好理解,就是从服务器拉回来的JSON数据。而持久化抽象模型暂时放在Model层,是因为MVVM诞生之初就没有对这块进行很细致的描述。按照经验,我们通常把数据库、文件操作封装成Model,并对外提供操作接口。(有些公司把数据存取操作单拎出来一层,称之为DataAdapter层,所以在业内会有很多MVVM的变种,但其本质上都是MVVM)。
Binder:MVVM的灵魂。可惜在MVVM这几个英文单词中并没有它的一席之地,它的最主要作用是在View和ViewModel之间做了双向数据绑定。如果MVVM没有Binder,那么它与MVC的差异不是很大。
需要注意一点,View持有ViewModel,ViewModel不能持有View(即ViewModel不能依赖UIKit中任何东西)。有两个原因:一是为了ViewModel可测性,即单元测试方便进行;二是团队人员可分离开发。可总结为:更加干净的解耦。
存在的问题
MVVM公认的问题
学习成本高
绑定数据比较繁琐,容易引起crash
犹豫要不要引入RAC
问题1
任何新技术,新模式都是有学习成本,MVVM也不例外,但是并不是非常高,阅读相关文章,以及技术大咖做的demo,经过一两个需求就基本掌握了。
问题2
在不使用RAC的情况下,一般使用KVO、类KVO来解决,需要在初始时绑定,dealloc移除绑定,还要避免主动修改viewModel值造成UI的循环响应修改。的确,相对繁琐,但已经有其他开源方案可以解决,既方便,又安全。
问题3
(个人意见)如果非必需,建议不要引用RAC,有两个原因,一是因为RAC学习成本需要颠覆之前的开发方式;二是RAC对性能影响非常大,一个简单的数据响应也会生成非常多信号量。
问题不止这些
经过长时间的使用,发现MVVM的viewModel的确可以抽离V/VC中的业务逻辑,但是不同VM由于对外接口不统一,相似的业务,如果通过VM之间的继承,可以解决当时问题,但是随着迭代,判断逻辑越来越多;如果创建各自独立VM,部分能力又会重复造轮子。
例如,页面A某个功能需要,先判断登陆,再上传修改;页面B某个功能需要,先判断登陆,再查看信息。
方案一
viewModelB继承viewModelA,viewModelA声明一个nextActionAfterLoginCheck public方法。viewModelA登录判断后调用nextActionAfterLoginCheck,而viewModelB重写即可。
但后期需要页面A在登录增加封禁账号不能修改信息,那么页面A就不用调用nextActionAfterLoginCheck,但是页面B需要。这时可以再声明一个
-(bool)shouldToDoNextAction 方法,在登录判断后通过这个方法获取A、B各自返回值,决定是否调用nextActionAfterLoginCheck,既保证nextActionAfterLoginCheck业务独立性(不涉及账户相关判断),又保证继承关系不变。但是登录模块代码引入了新的判断,VM臃肿化前兆现象。
方案二
页面A、页面B各自拥有自己的viewModel,这样登录逻辑便重复,但是日后修改,两个页面独立,互不影响。
有没有更好的解决方案呢?
分析
对比一下前后功能
* 开始时,页面A、B所包含的功能:登录判断、上传修改、查看信息。
* 后期迭代,页面A增加:封禁用户判断。
表面上,造成VM臃肿隐患的原因,是既要保留公用登录模块的前提下,完成页面A新的业务需要,又要最小影响页面B,则需要增加判断完成。那进一步分析业务链路,发现最终的形态如下:
根本上,VM自身承担的业务定义、执行,造成了各个功能无法灵活组织,随时可变,每一个功能修改都有可能影响到其他业务。
解决方案
如果VM只承担业务定义呢?通俗一点的说法,V/VC告诉VM要做一个什么业务,VM定义这个业务需要哪几个功能,具体功能实现不在VM实现,那么VM在后期迭代中只需要更新定义即可,无非是增删改定义的几个功能而已。
用这个思路分析上面case,既然不用实现功能,那么viewModelB就不用继承viewModelB,两个页面独立,viewModelA业务定义:登录判断、封禁判断、上传修改,viewModelB业务定义:登录判断、查看信息。
如此分析,可以发现,每个功能都被拆分成了相对“干净”的最小功能,那么这些功能在哪里实现呢?暂且叫它业务中心(Service)吧,新MVVMS模型图如下:
技术调研
若要实现上面的方案,必须解决3个问题:
如何定义
结果如何返回
Service应该如何设计
需要一套语法解决定义
个人觉得VM最终目标只需要传入一串字符、参数,就能完成一个具体业务。那么定义了字符,就涉及到解析、翻译,借鉴编译原理,我们需要一套定义业务的语法。
将相对独立、闭环的功能,称为原子功能,每个原子功能为一个编码,相关功能为一个模块,一个模块为一个编码区。例如:账户为模块Account,则登录判断(Account01)、登录(Account02)、封禁判断(Account03);信息模块Info,上传修改(Info01)。
功能之间执行先后顺序、串行、并行、是否执行,通过操作符来决定。类似四则运算中,括号()决定执行的顺序,+、-、×、÷决定两侧的运算结果。那么可不可以定义+表示只有左侧执行成功,才执行右侧,-表示左侧执行失败再执行右侧呢?
那么按照上面的case,页面A的业务定义为:
(Account01-Account02)+Account03+Info01。
响应数据变化代替某个接口结果
通常我们是通过一个方法返回拿到结果,如果要拿到几个功能执行后的返回结果,这种方式便行不通。再加上原子功能要保持闭环,独立,不能相互依赖值传递,就更不能走传统方式。
将Model改造一下,使用监听者模式,页面需要监听哪些数据,就在初始化时注册,原子功能执行时,根据参数修改对应数据,页面实时响应数据变化即可。
Service设计
Service分为两部分:语法解析、原子功能模块注册+执行。考虑到后期模块积累过多,造成加载耗时,要支持分桶加载模块能力,例如:现在有A、B、C,3个模块,但是页面只需要调用A、C模块,那么在初始化时,可以指定自定义模块桶为:AC。
可行性分析
目前,2020年优酷相关业务建设中,有相关雏形,可以完成上述部分设计,但必须申明一点,框架还有不完善之处,后续会朝着这个方向继续探索。后续完善后,会及时更新本文档,以及对应技术文档。
好处是明显的,框架升级后,琐碎繁复的代码,再也不需要重新copy+修改,原子功能完成只需一次,但可多次使用,并且随着加入开发的同学增多,后续业务使用时,会越来越方便。
写在最后
MVVM优化后框架并不是最终解,就像文章开头讲的,本文只讨论开发模式的可能演化、优化方向;希望大家在评论区留言指正、交流。
END
长按扫描二维码关注凌云时刻
每日收获前沿技术与科技洞见
投稿及合作请联系邮箱:lingyunshike@163.com
MVVM后,下一代开发模式在哪?相关推荐
- 玩转Android之MVVM开发模式实战,炫酷的DataBinding!
原文:http://blog.csdn.net/u012702547/article/details/52077515 ---------------------------------------- ...
- 【三种常见架构开发模式:MVC、MVP、MVVM】
写目录 1.常见的三种开发模式 (1)MVC模式(感觉重点在view) (2) MVP模式 (感觉重点在 Presenter) (3)MVVM模式(感觉重点在VM,viewModel) 1.常见的三种 ...
- iOS OC mvvm开发模式
相信大家对MVC开发都已经不陌生了,最经典开发模式 MVC构成: M:model也就是数据模型 V:View视图 C:Controller控制器 Model和View是相互独立的.View只负责页面展 ...
- SpringBoot中配置为开发模式,代码修改后不用重新运行
场景 SpringBoot中配置为开发模式,修改代码后不用重新运行. 实现 打开pom.xml,添加依赖 <!-- 添加如下依赖,配置为开发模式,代码做了修改,不用重新运行--><! ...
- Android开发模式万佛朝中MVX(MVC、MVP、MVVM)
今天公司的测试服务器开小差了,后台被吐槽的体无完肤,虽然我们都知道跟他没有什么关系,但是生活需要乐趣,总要有人背锅,哈哈!~~~暂时没有环境开发了,那就分享一下之前做的一篇关于Android开发模式的 ...
- ThinkPHP怪现象:数据表新增字段后开发模式可更新运行模式无法更新
一.情况说明 一个已经发布的程序中,数据库原有表article,字段原有id.content.title三个字段,原程序可以正常运行,通过大D方法可以正常的更新数据库. 现在要对这个程序进行更新,数据 ...
- dao模式和前端控制器结合使用_前端技术及开发模式的演进,带你了解前端技术的前世今生...
先声明,本篇不会讲带有年代性的前端发展史,不讲故事,想了解的读者可以去查阅一些其他的资料和文章,本篇仅仅从技术发展角度结合案例分析,说明前端技术的发展和开发模式的演进变化.本篇内容重点说明PC端技术, ...
- Asp.Net Ajax的两种基本开发模式
Asp.Net Ajax的两种基本开发模式 引言 最近花了一些时间,将微软Asp.Net官方的Ajax视频全部看了一遍,地址是http://www.asp.net/learn/ajax-videos/ ...
- 前端技术及开发模式的演进,带你了解前端技术的前世今生
先声明,本篇不会讲带有年代性的前端发展史,不讲故事,想了解的读者可以去查阅一些其他的资料和文章,本篇仅仅从技术发展角度结合案例分析,说明前端技术的发展和开发模式的演进变化.本篇内容重点说明PC端技术, ...
- 转 下一代云计算模式:Docker正掀起个性化商业革命
下一代云计算模式:Docker正掀起个性化商业革命 作者: 吴宁川 来源: ITValue 发布时间: 2015-09-20 10:41 阅读: 14052 次 推荐: 26 原文链接 ...
最新文章
- linux sntp 代码,C语言window(linux)平台的SNTP实现
- python爬网页源码_python爬虫爬取网页的内容和网页源码不同?
- Tensorflow安装与测试
- 安卓APP动态调试技术
- 【codecombat】 试玩全攻略 第十四关 已知敌人
- osg 三维gis开发_三维GIS平台的可视化应用 (下)
- zookeeper专题:zookeeper集群模式下,leader选举流程分析
- [转] Agile Software Development 敏捷软件开发
- 阶段1 语言基础+高级_1-3-Java语言高级_09-基础加强_第2节 反射_8_反射_Class对象功能_获取Field...
- 物流管理系统(数据库+后台+springMVC+Mybatis+layui)(一)
- Nodejs BFF 开发 8 个月的心路历程
- 计算机网络常用端口号大全
- 地壳中元素含量排名记忆口诀_【化学好好玩】用口诀帮你速记忆化学知识
- 计算机现在追寻谁的原理,一路追寻-CS考研经验总结_计算机与软件_考研论坛(kaoyan.com)...
- 长江大学计算机科学学院德贵奖学金,关于做好2019年各类奖学金评选的通知
- 用php获取设备信息
- 仿抖音效果的数字时钟罗盘
- 国际标准书号 (International Standard Book Number, ISBN)是专门为识别图书等文献而设计的国际编号
- 服务器硬盘选金盘好吗,WD 西部数据 企业级 10T金盘与8T金盘 对比测试
- virtualBox新建虚拟电脑
热门文章
- 批量删除2012年9月份以前的表
- 【技术贴】解决开机本地连接出来慢,本地连接开机后出来时间慢
- ubuntu下切换到root用户
- LCS2005标准版部署
- web调试代理工具Whistle
- solrCloud相关的管理命令
- BZOJ4602: [Sdoi2016]齿轮(并查集 启发式合并)
- jquery 给a标签加上或去掉下划线
- 固定背景图的高度,让宽度自适应
- 转:zTree树控件入门之checkbox:如何动态设置节点的checkbox选择框启用与禁用状态(chkDisabled)...