简称:MVP 全称:Model-View-Presenter ;MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方,Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示
模式特点
1.MVP是根据MVC演变而来
3.在MVC中,View是可以直接访问Model的!从而,View里会包含Model信息,不可避免的会包括一些业务逻辑。 在MVC模型里,更关注的Model的改变,而同时有多个对Model的不同显示,即View。所以,在MVC模型里,Model不依赖于View,但是View是依赖于Model的。不仅如此,因为有一些业务逻辑在View里实现了,导致要更改View也是比较困难的,至少有些业务逻辑是无法重用的。
2.在MVP中 : View并不直接使用Model,它们之间的通信是通过Presenter (也就是MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会直接从Model中读取数据而不是通过 Controller。
总结:
虽然 MVC 中的 View可以访问 Model,但是我们不建议在 View 中依赖 Model,而是要求尽可能把所有业务逻辑都放在 Controller 中处理,而 View只和 Controller 交互。
解决方式:
在MVP里,Presenter完全把Model和View进行了分离,主要的程序逻辑在Presenter里实现。而且,Presenter与具体的View是没有直接关联的,而是通过定义好的接口进行交互,从而使得在变更View时候可以保持Presenter的不变,即重用! 不仅如此,我们还可以编写测试用的View,模拟用户的各种操作,从而实现对Presenter的测试--而不需要使用自动化的测试工具。 我们甚至可以在Model和View都没有完成时候,就可以通过编写Mock Object(即实现了Model和View的接口,但没有具体的内容的)来测试Presenter的逻辑。 在MVP里,应用程序的逻辑主要在Presenter里实现,其中的View是很薄的一层。因此就有人提出了Presenter First的设计模式,就是根据User Story来首先设计和开发Presenter。在这个过程中,View是很简单的,能够把信息显示清楚就可以了。在后面,根据需要再随便更改View,而对Presenter没有任何的影响了。 如果要实现的UI比较复杂,而且相关的显示逻辑还跟Model有关系,就可以在View和Presenter之间放置一个Adapter。由这个 Adapter来访问Model和View,避免两者之间的关联。而同时,因为Adapter实现了View的接口,从而可以保证与Presenter之间接口的不变。这样就可以保证View和Presenter之间接口的简洁,又不失去UI的灵活性。 在MVP模式里,View只应该有简单的Set/Get的方法,用户输入和设置界面显示的内容,除此就不应该有更多的内容,绝不容许直接访问Model,这就是与MVC很大的不同之处。
优点:
1.分离了视图逻辑和业务逻辑,降低了耦合
2.Activity 只处理生命周期的任务,代码变得更加简洁
3.视图逻辑和业务逻辑分别抽象到了 View 和 Presenter 的接口中去,提高代码的可阅读性
4.Presenter 被抽象成接口,可以有多种具体的实现,所以方便进行单元测试
5.把业务逻辑抽到 Presenter 中去,避免后台线程引用着 Activity 导致 Activity 的资源无法被系统回收从而引起内存泄露和 OOM
缺点:
由于对视图的渲染放在了Presenter中,所以视图和Presenter的交互会过于频繁。还有一点需要明白,如果Presenter过多地渲染了视图,往往会使得它与特定的视图的联系过于紧密。一旦视图需要变更,那么Presenter也需要变更了。比如说,原本用来呈现Html的Presenter现在也需要用于呈现Pdf了,那么视图很有可能也需要变更。
下面请看代码实现:
一、不使用MVP的代码
下面开始采用最简单的MVP模式来改造这个代码:
1.创建一个类,用来封装网络请求(M层)
2.先定义一个接口,针对这个界面逻辑View需要作出的动作。
3.再创建一个类,用来处理M层和V层之间的通信,(P层)
4、让Activity实现这个接口中的方法(V层)
上面这4步是最基本的MVP模式,但是这样写会内存泄漏,因为如果在网络请求的过程中Activity关闭了,Presenter还持有V层的引用.
解决:
在Presenter添加绑定和解绑方法,断开网络方法:
修改后的activity:
这样我们就解决了内存泄露的问题,但是这样还是不完美,应用中肯定不可能只有一个模块,每个模块都对应着一个V层和P层,那这样的话每个Presenter中都要定义绑定和解绑的方法,而Activity中对应的也要调用这绑定和解绑的两个方法,代码冗余。
解决:
1.创建一个基类View,让所有View接口都必须实现,用来约束类型的
2.创建一个基类Presenter,在类上规定View泛型,然后定义绑定和解绑的抽象方法,让子类去实现,对外在提供一个获取View的方法,
让子类直接通过方法来获取View
3.创建一个基类的Activity,声明一个创建Presenter的抽象方法,因为要帮子类去绑定和解绑那么就需要拿到子类的Presenter才行,但是又不能随便一个类都能绑定的,因为只有基类的Presenter中才定义了绑定和解绑的方法,所以同样的在类上可以声明泛型,在方法上使用泛型来达到目的。
4.修改Presenter和Activity中的代码,各自继承自己的基类并去除重复代码
待续!