在目前的Android开发中,MVP与MVC架构还有MVVM都非常流行,三者在不同的场景下都有各自的优势和劣势,一般而言会根据具体的业务场景来选择不同的模式,所以并不是说开发一个App一定完全遵循那种模式,完全可以根据业务场景不同混合多种模式。
从概念上讲,MVP和MVC虽然都含有Model和View,但是Model和View的职责并不相同。下面是MVC和MVP的结构示意图
在MVC中,箭头的方向A->B可以简单的理解为A在代码中出现了B,例如Controller->Model,可以理解为Activity有一个成员变量User,Controller<->View可以理解为activity中有一个成员变量textview,textview也持有context(activity)这个对象。
而在MVP中,View和Model完全分离,通过中间的Presenter来传递消息。
Android的MVC并不是严格标准的MVC。
在Android中,通常而言M指的是数据模型(model类),V指的是XML文件和各种View组件,Controller则是Activity,Fragment这些带有生命周期的具体业务类。可是,Activity天生并不适合做Controller,因为View一定会在Activity中进行绑定(findviewbyid),所以Activity不可避免的还要做一些MVC中View的工作。因此,在Android的MVC中,Activity即是View又是Controller。这就导致了在一个业务复杂的Activity中,存在一大堆业务代码和UI控制代码,显的很臃肿,不利于维护和测试。
MVP可以很好的解决这个问题,在MVP中,我们就让Activity做一个纯粹的View,把具体的业务都剥离出去让Presenter做,每一个Presenter做不同的业务,这样就很方便维护和测试。
拿一个非常简单的登录界面来讲,我们现在要完成一个简单的业务,输入账号密码登录。
我们要完成四个功能:密码为空给出提示,账号为空给出提示,登录失败给出提示,登录成功显示欢迎xxx。
首先是使用MVC来完成这个业务,Api是一个模拟登录Api的类,SimpleDialog简单的封装了Dialog,可以忽略这些,具体代码可到文章末尾github地址查看。
在这个Activity即Controller中,持有了Model和一些View,同时Controller也做了部分View的工作。
再来是MVP模式,一个最简单的MVP模式由IView接口类(定义界面什么时候改变),Presenter(具体业务)和一个Activity(界面显示+控制)组成,如下面三张图的代码所示。
我们发现,在这个MVP模式的Activity中,Api的请求没有了,非法账号密码的判断也没有了,而且Activity不再持有model类(user对象),activity只调用了presenter的具体业务方法,然后这些全由presenter负责,Activity现在看起来完全是一个View,只管怎么显示界面。
当presenter完成业务后,势必要通知Activity对UI进行更改,我们定义了一个ILoginView接口,它确定了有哪些情况需要更改View,非常清晰。下面是ILoginView的代码,这四个接口分别是登录成功后ui的更改,因为登录成功后需要显示用户名字,所以传递了String的参数,其余三个为登录失败,非法的密码和非法的账号ui更新接口,根据业务的需要可以扩充这个接口和参数。
接下来看看最神奇的presenter类,其实presenter也并没有那么神奇,仅仅是把MVC中activity的业务代码挪到了这里面,在这个presenter中,一定要传入ILoginView这个接口,同时现在他持有了Model(即user对象)而不再是Activity持有User,在LoginPresenter完成登录业务后,调用IlongView接口来通知Activity更改页面。
现在回过头去看最初的结构图,应该能大致明白MVP的结构了吧。
MVP的好处就是剥离一个个业务,想象一下如果在这个界面增加注册,找回密码等业务,只要多增加几个presenter就可以了,而传统的MVC,把所有代码挤在Activity里,整个Activity是不是已经显的臃肿不堪。
项目地址
https://github.com/ccyzml/LoginCaseOnMVPMVC