Android中的MVC

来源:互联网 发布:数组去重复js 编辑:程序博客网 时间:2024/06/05 17:21

Android中的mvc

MVC架构起源于二十世纪八十年代,Xerox PARC为编程语言Smalltalk80发明的一种软件设计模式。但真正让它流行起来的,还是在Web程序被广泛开发之后。我接触MVC也是在开发各种web程序的时候,由于做外包的原因,接触了各种各样的MVC框架,各自有各自的有点,但宗旨都在于封装和复用。Android开发并没有强行让使用者使用MVC框架,但作为一个真特么好用的模式,MVC的加入也可以让Android客户端写得特别灵活。

为什么突然想写这个

突然想分享一下自己做了两年Android的感受,其实内容都是很浅显的东西。但工作中反复给大家提到了这样一些思路,说明这些内容还是有价值的,有那么一些人读了会受益。所以我决定写一写,我喜欢Android开发,我希望大家写的程序都具备严密的逻辑性。

虽然写技术类文章的结局总是被N个月之后的自己鄙视(这就是为啥我不太喜欢写技术博客的原因)。但是突然觉得,这至少证明我来过,我曾今是这样。

什么是MVC

什么是MVC百度说得很清楚了,但是还是有一些我觉得还可以说说的。

1、MVC其实是一个无限递归的过程,从一个普通的无线产品来看,服务端承载着MC,客户端是V。在一个客户端程序中又可以分开为MVC架构,M是服务端的数据、缓存等,V是展现,C来控制如何展现。在某一个服务端的M中,又可以区分出MVC……如此无限细腻的分下去。到底细到哪个程度,取决于这个软件到底有多复杂。

2、说到架构设计,很多人认为那都是CTO、首席架构师什么的才做的事情。其实不然,任何一个小模块、小功能,如果我们利用MVC的架构去设计、去实现都会让我们的代码看起来“就是不一样”,所以人人都应该有架构设计意识。

3、MVC与其说是一种框架,不如说是一种思想。在实际开发过程中,我们可能做出来的架构并没有model或者并没有Controller,或者View就是一个简单的JSON output。但这没有关系,只要结构合理完成MVC应该完成的任务就OK

4、什么时候应该应用MVC思想?这个界定其实很简单,很多讲编程思想的书会告诉你单个源码文件最好不要超过1000行,单个函数不要超过200行。因为太多就违反了单一职责原则会导致不好维护。那么应用MVC思想的场景也就是当我们把一个功能拆分为两个源码文件的时候。

Android中的MVC

Android中应用MVC,其中M一般有如下几种:数据库、缓存、SharePreference等,用于管理和处理数据。这和大多数MVC结构中的M并没有什么特别的地方,只是来源比较广。

但是应用View层就有说法了,很多文章都认为Android中的View应该就是那些XML布局,明显区别于JAVA代码的东西。但是我认为用这样的方法划分MVC不科学。和大紫大红的WEB MVC框架中大多数把HTML作为View一样,Android中的View也必须是包含代码并且可以继续拆分的。只是Android中的View依然使用JAVA代码,HTML这个View使用JS代码。总之一切和界面相关的代码都是View层,包括但不仅限于XML布局。

Controller还是那个Controller,承上启下。把model的旨意正确的传达给View。把View的反馈正确的写进model

小模块中的MVC应用——报警模块

虽然MVC设计模式和GOF的设计模式讲的并不是一个东东,但他们都适用于“重构到模式”这样一种简单的思想。最近就在一个小项目中得以表现。

初期的产品设计是这样的:我们的APP要检测设备电量(可以理解成读一个API取个数),如果电量低了(判断下阀值)就要给用户提示报警,用户点击了“取消报警”然后报警就取消了,我们需要这么个红色报警框。由于需求很简单程序员A就简单的在Activity里写了一个控制报警TextView的代码,并且随手写了个Timer定时检查报警状态。


紧接着就不对了,真的只有低电压需要报警吗?非也。好多东西都需要在这里报警。还没发版Doge就又提了一堆需要报警的东东。除了低电压报警,还有弱信号报警、转速过高报警、温度过高报警、操作失误报警瞬态错误报警(某种Exception……。其它的都还好说,无非就是check的时候多读几次API,但标蓝的这俩就不那么乖了,它是外部传递过来的信息,并不适合timercheck。程序员A还是硬着头皮写了。

 

由于读的东西很多,checkAndSetAlert散发着一股不可描述的味道……而且更蛋疼的是由于空间有限,每次能呈现的报警只有一条。各路报警目前都是后来挤先到的状态,Doge不满意。提出要求Alert要分优先级,按照优先级进行展示,展示Alert维护一条队列点完一个弹下一个,直到所有Alert都被呈现了。另外Alert也需要进行改造,要加一些酷炫的动画效果,最好还能BB叫提醒用户(一坨乱七八糟的代码)来强烈的提醒用户,Doge想交给程序员B来做。看到这样的需求,程序员B的内心是这样的:

 

虽然MainActivity变得臃肿,但总之还是能改的。于是MainActivity迎来了它最最臃肿的时期。大致的MainActivity画像就不贴了,自行脑补。

这事儿整到这个地步,不得不认真考虑下这个Alert的复杂程度和未来的复杂程度走势了。考察之后结论是:必须还会变的更复杂!这个时候我们就需要用“架构设计”来解决这个问题了,而我首先想到的就是应用MVC架构。那么究竟这些问题该如何分别给M\V\C三个部分合适呢?这就要分析需求变化点了,和Doge交流了下以后这玩意会变成什么样,Doge告诉程序员A他想把这个Alert做成整个系统的通用报警模块,有什么要报警的都丢给它处理。然后他们就梳理了一下以后可能发展的方向:1、报警展示Alert应该还会改,这么一个报警框可能都会不够用,效果也应该会再增加几种。2、根据权值进行Alert排序应该是最终的效果了。3、报警的来源是多元化的,传感器是一部分,传感器的判定报警逻辑可能还会更复杂。除了传感器数据,还有一些临时的东西要报警,比如瞬态错误。根据这些信息,我想了想做了以下决定。目的就是封装变化点,增加复用,方便维护。

View:把Alert进行封装,什么酷炫的效果都在Alert类里实现,对外暴露一个相对固定的接口来让它工作就可以了,同时提供点击回调,至于回调里怎么处理,还是交给Controller吧。这里把它叫做AlertView。它主要提供如下内容

 

Controller:如果业务逻辑没有足够复杂,它可以和view或者module写在一起,这也是通常的做法。但这里显然逻辑足够复杂了。Controller负责维护维护报警队列,把正确的报警传递到正确的Alert(隐隐感觉到,以后会有多个AlertView,有的还是报警框,有的应该是MessageBox了)。所以这个承上启下的东东,大致有这么几个功能。

 

model:如果把所有需要Alert的模型、数据都放在这里显然不合适,这里的model只是传感器的model,负责传感器的数据和传感器的逻辑。虽然大多数传感器都是单纯的阀值触发,但有些处理也挺复杂,比如延迟报警。每次获取延迟后需要做平滑处理,平滑后还超阀值才报警。所以我把这些破逻辑都甩给了传感器SenserModule。除此之外还有别的一些model会报警,各有各的吧,whatever。但他们使用报警,终归就是调用ControllerstartAlert

好了,这个小模块的MVC架构就出来。Module想展示Alert的时候,他只需要让ControllerstartAlertOK,至于最终到底show出来了没,什么时候show出来。都是Controller控制。Module发出的Alert到底发生了啥,通过AlertEvent回传给Module。如果Module无需关心,这个回调传个NULLOK。从显示端来看,它也无需考虑这Alert是怎么来的。它只负责它的效果就OK

好处呢?

可以看出,虽然用了MVC但代码量可是一丁点儿也没减少!文件还变多了。但是它带来了更强的框架复用性和可维护性。就目前这玩意,好处体现得有点快……

1、程序员B是一个很有设计能力的程序员,可惜程序功底略欠火候(这并不影响他是一个非常有设计能力的程序员)。UI方面的东东肯定交给他去做啦,新的MVC架构他是第一个受益的!因为他感到他终于不用去理解那些烦人的复杂逻辑了。

2、新的需求滚滚来,很快Doge发现有些报警只需要闪下红色报警框就行了,酷炫的动画省省吧。还有些报警甚至颜色都应该从红色移成黄色,这只取决于piority。新框架下要改这个就容易多了!程序员AB商量了下,让B给个新接口“style”来决定Alert的样式。然后自己把Controller拉来小小的修改了一下,Bingo

3Module端就不说了,完全封装后任何想AlertModulestartAlert一下就OK,剩下的都不会错!

这就是架构的力量,并不是CTO的工作也不是架构师的工作,这就是一个普通程序员A的工作。

4Doge觉得这个AlertView呈现形式太单一了,我们要扩展AlertBoxAlertActivity……

一些心得

这个小模块代码来自于我的一个拉锯战小项目。两年前我对Android一窍不通的时候开始写,写到现在还在写的一个小东东,这个报警模块也是真实发生的故事。Doge其实就是我,我也是程序员A。程序员B是我一好友Prolq,他的确是很有设计天赋的程序员!一开始Alert做出来并没有模式,混沌。我就把它重构到了现在这个状态。重构的时候并没有想到要用什么模式什么架构,但重构完了回过头来看,这就是一个典型的MVC应用,虽然M端千奇百怪但通过Controller的整合,他们变得很可爱了。

在工作中,我也常常对大小模块进行重构到模式,甚至有时候会有强烈的程序洁癖,对模块间恶意打洞只为图需求完成得快深恶痛绝。但自己进行重构的时机也一般是程序复杂得鲁棒性完全无法保证的时候,或许这也是最好的时候。但是重构总是费精力的,我们如何在设计的时候就把它规划好呢?要做到这件事,就需要程序员有用很强的产品思维。

程序员的产品思维

做任何架构设计都挺累的,而且非常容易过度设计,为了实现架构花了很大的力气,最终发现并没有任何卵用,实际这模块承载的内容就那么一丢丢!实际操作中很多程序员就不再想着设计架构了,怎么完成需求快怎么弄,who care?但做长远计划,有一个好的架构才能真正的快速完成需求。

要把一个模块设计得刚刚好,关键在于对需求的把握。这就需要程序员有一颗产品的心!产品最大的职责是选一件对的事情做,而程序员最大的职责是产品的把事情做对。所以一个程序员如果做不到大局观不会太影响他成为一个优秀的程序员,但如果针对某一件具体要做的事,还分析不出这件事短时间内的形态和以后的走势,就很难把事情做对了。拿到需求,站在产品的角度看问题,这个功能有啥用?以后还可能怎么扩展?最可能的需求变化点在哪里?这都是程序员要考虑的问题。如果实在把握不了也可以直接和产品沟通,如果产品认为此功能以后必成大器,我们要从xxxxxxx方面大幅扩展。那么注意了:赶紧变身架构狮。如果产品认为我们只是试一下,那么就跟产品讨论下我们到底要不要图快赶工。当然这个时候Doge一般会说:这件事就是我们未来的希望,而且上面催得挺紧的,也不难,你看明天完工行不行?

2 0