细数android中MVP的“七宗罪”

前言

我们都知道,MVP是在MVC的基础上做了一次升级,相比MVC,MVP中P层与V层隔离,V层只负责UI,业务逻辑由抽象出来的P层负责,真正意义上的隔离View的细节和复杂性的模式.......

好了好了,上面是网上MVP“鼓吹”的基本套路。“欲想让其灭亡,必先使其膨胀”今天,反其道而行之,我们来罗列MVP的“七宗罪”

MVP的“七宗罪”

有一定经验的工程师都知道,我们的java有六大基本原则,我们在编程的时候,应该尽量去遵循面向对象思想,遵循六大基本原则。而有时候,为了“合理”,我们会多绕很多“弯路”,比如要实现降低类间的耦合,不得已我们会写出很多接口,这就造成了代码膨胀。耦合度与代码量之间,我们常常要做到取舍,没有绝对的合理,只有相对的优化。MVP在追求它的自身理念的同时,也“不小心”违背了部分原则。

在开头,先简单来看看MVP的缺点

1.粒度不好控制,控制不好就需要写过多的类和接口
2.如要重用presenter可能会实现过多不需要的接口
3.Presenter和View通过接口通信太繁琐,一旦View层需要的数据变化,那么对应的接口就需要更改

违背开闭原则

我认为MVP设计的初衷是MVP三层分别用中间件衔接,三者可分由不同开发者开发,相互间实现无缝衔接。在MVP中,只有P层负责逻辑,具有独立意志与决定权,是三层的主导,而V与M都只是工具,,V与M层的替换应该是得非常简单。

可是,在实际中,V层与P层依赖性太强,V确实与M分开了,可是当我们业务涉及了视觉交互,UI逻辑要修改时,V与P相牵连,都要配合做改动,这样就做不到我们上面初衷所设想的,P层编写者要不断被不是本质工作的任务牵连,着违背了开放封闭原则。形式上解耦,但是职责分工还是耦合。

违背单一职责原则(可解决)

在项目中,如果有fragment,我们经常把fragment作为V层,为了降低V与P的耦合,会在其主activity中去实例化P层的接口,这里,我们是不把activity当初V层,而实际上,activity就应该是V层的一部分,如果把它当做V层,那V层持有P层的引用,这违背了单一职责原则。实际上,借助其他工具库是可以解决这个问题的。用Dagger2,实现“依赖注入,控制反转”,不由调用者决定调用谁,把控制的主导权交给被注入者来决定,这就符合了单一职责原则,V层专心UI工作,如果要替换被注入的类,由注入者来改,调用者是感知不到的变化,不改动代码,从而减低耦合。实际上,解决方法已经在上文给出了。

违背迪米特原则

迪米特也就最少知道原则,这部分与上面开闭原则比较像,不做展开(像指定是导致违背原因相像,而不是原则本身像)

违背接口隔离原则(可解决,比较麻烦)

由回到了我们上面的问题,MVP中,一大难题是如何控制好P层接口的粒度,如果粒度太小,那么一旦业务多起来,我们的P层会非常臃肿。而如果粒度太小,那么我们一个P层确实可以达到复用,可却导致了我们不同需求的V层复用同一个P层接口时,要实现好多我们不需要的方法,这就是非常典型的违背了接口隔离,接口的实现类不应该实现没有的方法。

如果把控好P层的粒度可以解决这个问题,不过,在项目一开始就能把控好我们的业务,这要求对业务及代码的掌控能力比较强,这是比较考验经验的,所以解决其来也不简单。而且,我认为接口的一个好处是可以在一开始对该接口的实现类有一个大体的把控,起到了引导的作用。如果这样看,那么多写接口未必是坏事,相反,为了避免P层膨胀,强行让接口可复用,这就导致接口成为了代码的“束缚”。

违背依赖倒置与里氏替换原则

??!!

我数着基本原则也就六个,这是全都搞砸了??!!

好啦好啦,这两个纯属开玩笑的,再违背下去,MVP都快要“十恶不赦”了。

那么有人会说,你这不是“杠精”吗,欲加之罪何患无辞!照你这么说,MVP怎么可能会有人用,这不是吹毛求疵吗?

非也非也,MVP能做到成为主流的框架,自然有他的很多优势。这里我强行“抬杠”,不是说它不好,只是在强调它不一定就合适。

我所想表达的是,在开发中,我们选择主流的不一定就是对的,比如我们选择图片加载框架,我们看到Glide封装的最完善易用,我们就贸然使用了它,却没考虑到他的库非常占内存,其他库也许更合适。

本文意义所在

在开发过程中,最难的并不是完成应用的开发工作,而是在后续扩展维护的过程,如何让应用系统能拥抱不断的变化迭代,在不破坏原有稳定性的基础上提高可扩展性,达到高内聚,低耦合。这是为什么要追求稳定的系统框架设计。

回到主题,上面列举其违背原则,是想说,我们的MVP在实际不同的项目中,并不是一成不变的,根据不同的情况我们可能会在MVP的基础上做改动。比如某公司由于人员分配,V层与P层有不同团队人员并行开发,那么为了做到彼此并行,那么我们就会像我上面强行“抬杠”那样,要求其解决“接口隔离,单一职责原则的问题”,解决粒度的问题。具体做法可能会是在MVP基础上,在V与P之间加一层路由,实现解耦,也可以是通过使用LiveData+ViewModel,甚至使用EventBus来实现各层之间的通讯。不同情况不同做法,编程是没有一套绝对的标准,这些都是要根据需求,根据人员配置,选择合适的做法,并接受其带来的弊端。

我们的MVP在大的项目中的使用相对还是比较得心应手的,但是,如果你的项目不大,并且由一个人开发。你强行使用MVP,那么你项目的前期可能得重复写好多接口,这很让人头大。

相比MVP,MVVM在某些方面更加友好,其实好多有经验的工程师,更倾向于在MVP与MVVM之间取得一个折中,一种比较优雅的写法是MVP+LiveData+ModeView+LifeCycle+Dagger2。

有的人看到这里已经坐不住了,别急,都看到这了,那我就不往下讲了。。。。。。。。。。。

哈哈,开玩笑的。关于架构的选择与优化,我会在后面搞一个比较详细的系列来与大家一起交流学习。涉及了MVVM,架构组件,以及对于MVVM与MVP的优化。本文仅作为该系列的引子。旨在追求一套适合个人的框架。

谢谢你的阅读,如果有收获,不要吝惜你的点赞。如果有偏颇,请你指出,相互学习进步。谢谢你!

猜你喜欢

转载自blog.csdn.net/qq_39037047/article/details/84330535