对MVP、Flux和RxAndroid框架的理解和选择

为什么要使用框架

使用框架,是为了提高生产效率。

什么是生产效率?

上学的时候,导师曾说:我以前上学那会儿,什么都得自己写,别的不说,光把界面画出来就够发表篇论文了,哪像你们现在,拿个鼠标拖几下就能弄出界面来。

这就是生产效率。

为什么使用框架能提高生产效率?

做过软件的人都知道,我们开发一个软件,其实就是把现实中的业务映射到软件中去,这是一个对现实去做软件建模,去做代码实现的过程,而现实又是极度复杂的,做工程的基本常识是,越复杂的东西风险就越高,所以软件开发是充满未知风险的,面对未知风险,我们是茫然且恐惧的,在茫然之下,我们最直接的反应是:这种事一般要怎样做,有什么经验,有没有什么套路。

框架就是这样一种套路,因为它已经通过某种范式,完成了对业务的解析、映射和分层,在充满未知的软件开发中,框架的存在使开发有一定规矩可循,使常见的问题容易得到解决,使开发人员更专注于具体业务。

一般来说,使用框架有这样几点好处:

1、加快开发速度。很多框架会帮你实现一些通用的、偏底层的实现、例如用IDE绘制软件界面、用Hibernate读写数据库、用EventBus传递事件、用HttpClient处理网络请求等(Android开发的框架会更多一些),除非是特殊的环境或有特别的诉求,否则没有开发者愿意花费大量的时间和精力,自己再造一遍轮子。

2、降低开发风险。还是造轮子的问题,每个轮子都会有缺陷,但是大家都在用的轮子,相对更加可靠,发现缺陷也容易及时得到修复。

3、方便团队协作。一般情况下,软件开发都是团队行为,团队开发就要求在成员之间协调一致地并行工作,这就要求接口一致、风格一致等,这会带来很多管理上的问题,而使用框架能较好地辅助这一点。

4、框架本身的优势。每个框架的出现都是为了解决某些问题,像我们今天要讨论的MVP、Flux和RxAndroid,都是为了解决日益复杂的业务逻辑导致软件不可控的问题,MVP的思路是“挪”,在MVC的基础上把业务逻辑从View中挪走;Flux的思路是“单向流”,用严格的单向数据流去实现比较容易跟踪检测的逻辑结构;RxAndroid的思路则是“链式逻辑”,用函数反应式编程的思想把逻辑、代码和线程统统简化为一条链式调用。

MVP

关于MVP的经典表述可以参考Google开源项目Android Architecture Blueprints

MVP想解决的问题是,Google原来为Android准备的MVC分层架构中,C的存在极其薄弱,存在严重的Activity膨胀的问题,在很多开发中,Activity既是显示界面,又是业务逻辑,从一开始就没有分散职能,Activity会随着业务的变化急速膨胀,逻辑膨胀,代码膨胀,文件膨胀,长期连续迭代下来,一个Activity的代码很容易拖到几千行甚至上万行,代码的复用性、可读性和可维护性都变得非常糟糕。

膨胀的Activity

这种情况下,一个比较合理的思路就是“挪”,把业务逻辑从Activity中挪出来,挪到Presenter中去,让Activity回归View的角色,从此Presenter专注于业务,View专注于显示。业务逻辑不再受Activity生命周期的影响,Activity也摆脱了业务逻辑无法复用的囧境。

用MVP对Activity瘦身

“挪”业务逻辑的MVP,基本解决了Activity膨胀的问题,View层变得相对简单而安全了,而Presenter层中的业务逻辑,也比较容易做单元测试,做代码复用,做进一步的抽象和分离。

但是MVP中的业务逻辑仍然复杂,而且逻辑流和数据流基本处于只要不出bug,就可以放任自流的状态,体现在业务逻辑上就是无数错综交叉的业务线,体现在业务数据(Model)上就是无数的调用入口,长期运转下来,会发现越复杂的业务就越难以追踪逻辑运转和数据状态,对软件的维护扩展非常不利。

MVP的业务逻辑

也就是说,MVP需要一个状态管理工具,用来督促开发者按照一定规律处理状态的读写,避免代码变成一团乱麻。

Flux

关于Flux的经典内容可以参考Facebook的移动架构Android Flux

Flux试图用“单向流”去实现状态管理,它是一个单向绑定的单向数据流结构,一般我们看到的图是这样子的:

Flux结构

Flux是一个单向环,它实现业务的基本流程如下:

1、View响应操作并创建对应的Action

2、Action调用单例的Dispatcher去统一处理所有请求

3、Dispatcher持有所有Store对象,通过回调让Store处理数据

4、Store处理数据后,发出事件(EventBus)通知View更新解密

5、View接收Store的事件后,刷新页面

上面的图并不能表现Dispatcher的中心作用,我们可以看这个图:

复杂的Flux

可以看到,Flux实际上比MVP更啰嗦,要创建更多的对象,使用更多的订阅和回调,依赖EventBus去刷新页面...

但是,Flux能把所有的业务都引流到一个Dispatcher单例中处理,这实际上建立了一种机制,这种机制能在同一个地方查询状态、改变状态、传播状态的变化,这就是MVP缺少的那种状态管理工具。

在这种机制下,所有的业务都是从某处开始并进入Dispatcher,再离开Dispatcher去往某处结束,中间不可能有循环,每条业务逻辑都只朝着终点方向运行,这就实现了Flux“单向流”的思想,这就是单向数据流。

单向数据流对软件开发来说,意味着什么呢:

单向数据流

如上图所示,单向数据流,意味着业务逻辑得到了有效的管理,我们可以很清楚地知道每条业务线上会发生什么,不会发生什么,软件的状态和行为变得容易预测,代码的可读性和可预测性得到提高,业务流程得以简化,容易排除错误,这给开发和维护带来了极大的便利。

Flux当然也有问题,他太啰嗦,代码复用太差,会有严重的action类膨胀问题。感兴趣的开发者可以再去了解一下相对简洁许多的Redux,目前主要在web开发中和React一起使用,对Redux的介绍可以参考Redux中文文档

RxAndroid

RxAndroid其实就是在Android中使用RxJava,详细内容可以参考给 Android 开发者的 RxJava 详解

RxJava 是个了不起的工具,它使代码的编写和维护更加容易,而且更少出错,它的思路和MVP/Flux完全不同,如果说MVP/Flux关注的是类的分层和分工,那么RxJava关注的就是纯粹的业务逻辑链条。

RxJava的不同

RxJava通过订阅事件驱动的链式逻辑调用,把复杂的异步逻辑维持成为一条简单的链式结构,来保持逻辑和代码上的简洁,这也使业界普遍认为Rx编程属于“函数响应式编程(FRP)”,因为它好像不再依赖于通过面向对象(OO)的设计来解决问题,而是通过 “链式”的思维方式,实现基于订阅事件驱动的简洁的链式调用,订阅事件驱动的基本思想如下:

订阅事件驱动

用被观察者去发出事件,在观察者中响应事件,形成异常简洁的逻辑链条,这种简洁即是RxJava的魅力和优势所在。

一段RxJava的典型代码是这样的:

RxAndroid典型代码

我们看到,所有的事情都在同一个链式调用里完成了,其中的订阅和事件我们都不陌生,这也不是它保持简洁的秘诀,RxJava保持简洁的秘诀在于链式调用,而链式调用的秘诀在于,每次逻辑调用后返回的对象,都是自己或自己的同类,并包含了继续链式调用的方法。

链式调用

通过把复杂的业务维持成一条简单的链式结构,保持逻辑和代码上的简洁,这种做法的好处是显而易见的,简洁、优雅、高效,而且现实中的业务线几乎可以照葫芦画瓢地映射为代码中的逻辑链。

当然RxJava也有他的问题,就是对代码的掌控变弱了。能把复杂问题用简单形式表达出来当然很了不起,但是复杂逻辑被表达为简单链条后,一方面摆脱了臃肿的代码,另一方面却因为代码逻辑过于紧凑,给排查故障带来了障碍,比如说新手常犯的一个错误是,忘记将网络请求分配到异步线程去工作,而默认搭配的Retrofit网络框架是无法在Android主线程上工作的,整条业务链从一开始就中断了,但开发者能看到的直接反馈是业务链的结尾没有输出,很难精确定位到故障点,只好对整条链路进行检查,这对开发和维护也是不利的。

感兴趣的开发者也可以去阅读我以前写的文章RxAndroid使用初探—简洁、优雅、高效

如何选择

在框架的选择上,没有最好的框架,只有最合适的框架,特别是很多框架只是一种编程思想,你很难说自己在编程时会特意使用某种思想,又特意不使用某种思想,就像前些年热炒的设计模式一样,不要为了使用而使用,能恰到好处地需要解决你的问题,就是适合你的。

更详细点说,使用框架的问题不仅在于如何把框架应用到你的项目中,也在于如何在不必要用框架地方保持清爽简洁,比如如果你的页面非常简单,没有很多互动,就不要使用Rx、Redux、Flux,甚至MVP也不需要,你就简单地在一个Activity里实现就好。

总的来说,合适的就是最好的,不要过度设计,保留在必要时重构代码的能力就好。毕竟,对于软件工程来说,完备周全的设计往往起不到应有的作用,反而是快速交付,快速迭代的策略越来越被证明是一种低风险的模式,不过,这个话题就是另外一个范畴了。

参考资料

Google开源项目Android Architecture Blueprints

Facebook的移动架构Android Flux

给 Android 开发者的 RxJava 详解

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,408评论 4 371
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,690评论 2 307
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,036评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,726评论 0 221
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,123评论 3 296
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,037评论 1 225
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,178评论 2 318
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,964评论 0 213
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,703评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,863评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,333评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,658评论 3 263
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,374评论 3 244
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,195评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,988评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,167评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,970评论 2 279

推荐阅读更多精彩内容