在“FluxJava: 给 Java 使用的 Flux 库”这篇文章中提到,设计中使用 MVP 最大的问题,是会让不同的画面形成一组、一组的 Class,但各组之间是独立的。MVP 最基本的设计概念中,只描述了同一组内 Class 如何互动,并没有提到组内的 Class 如何跨组与其他的 Class 互动。当设计上出现要跨组的情况时,就得要仰赖设计者的功力与经验了。
就 MVP 的精神,View 要负责的工作,只是把 Presenter 送来的 Model 内容呈现在画面上。并且,与使用者互动,接收使用者的意图、收集使用者输入的数据,再交由 Presenter 处理。至于其他与 Business Logic 有关的事,不会由 View 来经手。
画面的切换由谁负责
在只有单一画面的情况之下,看起来很合理、分工明确,在设计上应该是个无可挑剔的方案。只是当画面一多起来,随之出现了一个问题:画面的切换由谁负责?
有问题吗?View 是负责使用者互动的,当然画面的转换由 View 来做啰!
也对,以 Android 平台为例,发送 Intent 大多是在 Activity 或是 Fragment 上处理的,再自然不过了。等新的 View 被载入后,再去启动与其配对的 Presenter、让 Presenter 把数据送过来。流程上都还在设计的预想之内,跨组的工作的确就由 View 来完成即可。
在画面与画面的顺序固定的情况下,看起来是没什么问题。如果画面的切换要依据数据的状态来决定呢?
刚才有提到,为了保持每个 Class 任务的单纯性,View 应该与 Business Logic 无关。要让 View 根据数据状态来决定,某种程度上就是 Business Logic,这样是不是违反了一开始提到的精神?
而且判断时所依据的数据,很可能跟 View 要显示的内容无关,又或者是一个复杂的逻辑,又更加深了是否该放在 View 上的疑虑。
Presenter 是否要跨平台
不放在 View 又要放在哪?Presenter 上吗?
这应该是在简单的 MVP 结构之下,大多数人的选择。当整个结构中,就只有 Model、View、Presenter,自然是只能由 Presenter 来存取数据库、负责数据处理逻辑。此时再多加一项,依据数据决定画面切换方式,好像也没有什么不恰当。
先回到 Android 平台上,来看看这样的安排会出现什么情况。
Presenter 要能够控制 Activity 的转换,必须要取得 Context,这也意味着 Presenter 与 Android 平台绑在一起。所以当这样的设计内容,要移到不同的平台上,Presenter 就有可能要面临大幅度在设计上的修改。换句话说就是,把工作放在 Presenter 上,会将设计限制在特定的平台上。
把 Context 排除在 Presenter 之外,就可以避免这个问题了吗?
就算是 Presenter 不直接控制 Activity 的转换,只决定要切换哪一个 Activity,Presenter 势必要有 Activity 的资讯,不管是 Type 或是 Class 名称。换了一个平台,显示画面的 Class 还会是相同的名称吗?可以确定的是 Type 一定不一样。
MVP 套用在 Android 上的问题
那就不要跨平台,大不了新的平台把设计再重做一次!
其实对 Android 平台来说,问题还不止如此。以 Master-Detail 的画面配置当例子,不同屏幕尺寸的情况下,会有一个 Activity 和二个 Activity 的差别。
原本在大屏幕中,一个 View、一个 Presenter 就做完的事,到了小屏幕却变成二个 View,那 Presenter 也要跟着拆成二个?
假设答案是肯定的,也就是说同一个 App 里,同样用途的画面就做了三组 View/Presenter。不对,在 Android 的 Master-Detail 的模板中,Master 的 Activity 是共用的,那岂不变成同一个 View 有二个 Presenter 配对?
这样的设计好像有点累赘,但真的要在这样的设计下,把流程串起来也不是不行。不过,要由 Master-Detail 跳到其他画面的工作,应该三个 Presenter 都相同,是不是要抽离出来,不要在 Presenter 里做?
结果,画面切换要由谁负责的问题又绕回到原点。
当有使用 Service 或 BroadcastReceiver 的需求时,又会引发不同的问题。
没有套用 MVP 之前,都是很直觉地在 Activity 中进行 Service 的使用。Service 大部份是用来进行后端数据处理的作业,这样的 Service 该由 View 来启动吗?不是应该透过 Presenter?
现在前端不适合启动 Service,那该由谁接手?Presenter 吗?
是比 View 合适的选择,但这样又会回到 Presenter 要不要独立于平台之外的问题上。
再者,Service 完成作业之后,如果要以 BroadcastReceiver 的流程来通知外部。BroadcastReceiver 可以放在 Activity 上吗?MVP 传送数据不是都要透过 Presenter?Service 在用来处理数据时,算是后端,不用经过 Presenter 吗?
MVP 设计的下一步
在“MVC 与 MVP 的抉择”一文中提到,把 MVP 中的 View 视为 Sub System,其实并不是突发奇想。而是在导入 MVP 时,用来应对在设计上所碰到的诸多问题的一个环节。
如果要深入的说明整个构思的内容,由于篇幅可能会很大,未来在时间允许之下,会有更多有关这方面的文章来做讨论。
更多深入的文章请参阅 http://www.jianshu.com/u/fea63707e07f