MVP那些事儿(5) 中介者与MVP

1,398 阅读13分钟

目录

MVP那些事儿(1)……用场景说话

MVP那些事儿(2)……MVC架构初探

MVP那些事儿(3)……在Android中使用MVC(上)

MVP那些事儿(4)……在Android中使用MVC(下)

MVP那些事儿(5)……中介者模式与MVP的关系

MVP那些事儿(6)……MVC变身为MVP

MVP那些事儿(7)……Repository设计分析

快速回顾

MVP那些事儿(4)……在Android中使用MVC(下)

MVC的各个角色通过监听机制已经组合完成,且成了一条事件传送带,让事件流转其中,或许在以后,我们可以在这条带子上关键环节加入多个处理事件的方法,并把它们暴露出来供使用者自定义它们的具体功能,让其具备可扩展的特性。 这张图中的每一个虚线圆点,表示着对外暴露的可操作事件的方法,在设计框架的时候,扩展性可是是我们需要考虑的一个关键特性。

前言

之前已经通过很多的篇幅详细的介绍并搭建了MVC框架,目的是为了可以平滑的过渡到MVP,在开始之前,如果还有对MVC架构概念的理解有些模糊,可以回头看看之前的章节,本章的内容是将注意力放在MVC与MVP之间的不同点上,不会过多的阐述它们之间共通的部分。如果已经阅读了的朋友,结合本章内容你会相对轻松的理解并抓住MVP的本质。

有没有更具体的?

为了能更好的理解MVC与MVP的区别,就要把它们具象的去讨论,而尽量避免停留在抽象的层面。MVP的出现是弥补了MVC某一方面的不足,必然算是一种提升,而这提升的过程,必然也是思想的提升,但凡涉及到设计思想,也就逃不出大众的思维,我们在处理一些问题时,都会碰到一些阻碍,人们在处理这些问题时积累了些许经验,为了以后能少走弯路,就把这些经验流传下来总结成册,古有三十六计孙子兵法,今有GoF的二十三种设计模式,都是为了解决一些场景性的问题而制定的最优策略。所以,在MVC提升到MVP的过程中,会不会也有前人留下的设计思想值得我们去借鉴一下呢?在我专注MVP的时候,我发现了中介者设计模式与MVP的核心思想有很大程度的吻合,都有着“隔离、调度”的特性,相对于抽象的架构来说,设计模式从学习、理解更加的具体,更能起到抛砖引玉平滑过渡的作用,我也特别想从中介者模式的这个角度去谈谈MVC与MVP之间的本质区别,其主要目的还是希望能通过一个具象的例子,延伸到抽象的架构上去,让大家加深理解,抓住本质且灵活运用。

中介者模式(Mediator)

先抛出比较抽象的定义,中介者模式的出现是为了解决对象间复杂的引用关系,即“调度”。为了能快速了解中介者模式的核心价值,我们引入一个场景,更加具象的刨析这个定义,

场景描述

一部电影要开拍了,你是剧组里的演员,你有很多同事,比如同为演员的小妍,灯光:小光,武术指导:小武,场控、执行导演、管理道化服的同事等等,不管是什么样的团体或者组织,大伙协同工作的过程中一定避免不了的就是交流。

同事类(Colleague)

首先,从你的角度做为出发点,你的同事(演员,灯光,武术指导,执行导演,道化服)统一称之为同事类,其次,从其他同事的角度出发,你在别的同事眼中也是他们的同事类,你们是一类人,都可以叫做同事类,这是同事类的定义。

所谓的‘一类’,宽泛些是指有起码一个或以上的共通行为,在这里大家都是剧组的成员。

为这次工作增加点难度

1、由于前期筹划紧张,总导演没有到岗。

2、工期不等人,强行开工。

3、在没有人负责流程管理的情况下,沟通开始混乱。

下面,通过一副动图来体现一下“混乱”的沟通场景。

没有使用中介者

多想一步:如果我们将上面的场景设计成代码,会发现每个同事类都会依赖其他同事类对象,这显然是不太合理的,随着同事类的增加,这样的依赖关系也会随之增加,不难想象,这样的代码是难以进行维护和扩展的,这不难理解,对吧?

4、在整个剧组处于“混乱”时,谢天谢地,总导演终于到岗了,他决定出面解决这样的混乱,既然要麻烦人,就麻烦我一个人吧,逐决定:同事类所有的沟通都要先汇报到总导演,然后再让总导演做出决策并转发命令到相应的同事,禁止同事与同事间直接沟通,比如武术指导提出一个新的想法,先要传递到总导演处,再由总导演决定,到底需要那些同事参与这个新的想法。那这样,武术指导的唯一依赖只有总导演,而其他同事也都可以依赖总导演去与其他的同事沟通,看到这里总导演的决策是不是有中介者那味儿了。

多想一步:在工作中,我们经常通过微信群作为沟通的媒介,而这个群就是一个中介者的存在,所有人都可以将信息丢到这个群中,虽然“群”不会将这条信息主动分辨或者派发给这条信息的相关同事,但在这个群里的人都会注册并监听这个群,一旦发现和自己相关的信息(条件成立),便可以处理这条信息。所以可以总结为:群里的成员只和“群”有着唯一的依赖关系,不用和其他成员直接沟通也可以达到协同工作的目的,这也是中介者模式成立的唯一原则。

中介者的职责

通过上面的场景描述,我们渐渐的明白了在什么场景下需要中介者的介入,以及中介者这个角色的职责,和中介者模式成立的原则,在这里,总导演承担着中介者的职责,他相对于同事类来说是中介者类,在中介者设计模式只涉及到两个角色,同事与中介者。

中介者的职责就是让同事类之间“永不相见”——隔离。并负责收集传递同事间的事件在此期间做一些流程控制。

同事类的职责

同事类是可以有共通的行为,比如上班,下班,吃中饭。同事类也可以完全没有共通行为,比如有一类同事,它们可能只负责演戏,还有一类同事,它们可能只负责订饭,演戏的不会订饭,订饭的也不会演戏。

多想一步:为什么要强调共同的行为,在设计或编码过程中,我们习惯于将通用行为下沉,这个时候可能会抽象出一个“超级同事类”,我们通过“超级同事类”来描述同事类的行为,行为的下沉即意味者行为具有扩展性。

在了解中介者模式的使用场景后,我们通过一动图来解释一下有中介者(总导演)的剧组是如何沟通的:

使用中介者

所有的对象只和中介者交互,由中介者负责处理逻辑和转发事件,或者同事类主动监听中介者接收到的所有事件,是否处理事件由各个同事类自行决定(微信群的例子)。

多想一步:中介者会不会很胖?它揽下了大多数的职责,是不是会变的臃肿庞大?有两个点可以避免这样的问题:一、同事类尽可能的在自己的范围内处理必要的工作。二、实际使用中,中介者可以按照具体的场景进行分工协作,将工作进行分散处理,因为中介者也是一类角色,它会有很多个。

那么中介者模式和MVP架构有什么联系吗? 我们把上面的两张图简化一下,还记得我们之前是怎么介绍MVC的架构图吗?没错,把具象的变成抽象的。

抽象化

我们首先把同事类的个数从5个变为3个:

通过对同事类的减少,我们生成了一张对比图,左边的图是没有使用中介者的场景,右边的使用了中介者的场景。对于左边的图是不是有些似曾相识呢?如果大家看了我之前写的文章或者对MVC有了解的话,是不是很像MVC的架构图?再看看右边的图是不是有点像MVP呢?也许有人会有疑问,像是像,但一个是模式,用来解决实际问题,而另外一个是架构,不可以相提并论,当然我自己也在之前的文章里阐述过这个问题,设计模式和架构不是一个概念,解释一下,并没有说中介者模式就是MVP架构,而是借鉴了中介者模式中的部分思想,起码从个数来说,中介者同事类的个数是没有上限的,而MVP的同事只有2个,M和V,这里指的个数是同一类同事,并不是所有实例化的同事。当我们把具象的业务场景向上抽离直到变成抽象,最终我们发现,在中介者模式里的同事类,就如同MVC中的三个层,它们互为同事,不计耦合的成本点对点的通信,即Controller并没有起到隔离同事的作用,它就是一个普通的同事,而在MVP中,M与V是被隔离开来的,所有的沟通都要通过P来进行,这和中介者模式的思想是异曲同工的,只不过中介者更偏向于实际的场景,更加的具象而已。

多想一步

剧组不可能只有一个演员或者武术指导,更或者是导演(我们这里讨论的角色都是泛化前的,也就是接口)。举个例子,拍摄的过程中不知什么原因又换了一个导演,不管怎么换他的核心职责就是中介者,又或者换了一个演员,他可能有他独有的特性,但核心还是一个会演戏的同事类,在现实中,这种人员调动一定会存在的,如果大家都是点对点的沟通,那么耦合是在所难免,假设一个武术指导角色依赖了最少四个以上的其他同事,当这个武术指导不在了,或者需要替换,那么他们之间的行为都会消失无法利用。而有了中介者,同事间的沟通是不需要知道接受方是谁,这一切都由中介者去操心。而同事类也可以不用知道具体的中介类是谁,他们之间是绝对透明的,也许第二天你即时通讯软件里收到的信息是来自另外一个导演的指令,这也就是所谓的“封装/隔离”,也是接口的本质。

错综复杂的对象间关系

在中介者模式的章节里,我们知道这个模式的核心价值观是为了解决对象间错综复杂的关系,但除此之外,它还有一个非常酷的拓展能力,这也是MVP最为重要的一个能力——可复用与可扩展性。 复用性和可扩展性才是用好MVP的关键

MVP的扩展性

我们继续通过之前的场景来阐述MVP的扩展性,项目中一开始只开发了IOS平台的软件,这个时候公司决定增加Andoird平台,之前项目已经有了一个完整的团队,现在只需要加入一个Andoird程序员和一个熟悉Android设计的UI,因为IOS和Android程序员都有一个共同的能力,就是对接口理解,以及对设计和需求的理解是一致的,只不过他们使用的平台不一样,所以在泛化程序员的时候,我们只要把平台这一项放开即可,UI也是一样,他们使用的工具和设计稿相同,只不过切图的尺寸不同,而产品经理、项目经理、测试工程师、后台工程师都可以直接拿来复用,而不需要另外组建一个团队,这对公司来说是一件非常节省成本的事情,而同时,程序员组和UI组的到了能力扩展。 再继续举个例子,在项目的开展过程中,由于追赶进度,需要加班,而项目经理周六日无法加班,于是公司派了一个加班项目经理。他只有在周六日上班,由于是加班,所以加班项目经理决定下班时间从七点调整为五点,这样当项目处于加班期时,员工五点下班,我们的项目经理都有决定下班时间的功能,而这个功能是开放的。很不巧的是,我们的产品经理也需要一个加班产品经理,这个加班产品经理他根本不知道加班项目经理和项目经理之间的区别,他一直以为下班时间为五点,而事实上他无需关心,同样的,加班项目经理也不知道这个产品经理是个加班产品经理,他也无需关心这一点,他们之间永远都是透明的。 (仔细看这张图,慢慢体会)。

总结

我们看似是在讲中介者,其实只是通过中介者来论述MVP架构的优势, 中介者模式的出现是为了解决对象间错中复杂的关系,在没有中介者的情况下,所有对象都要认识彼此,有了中介者,它包含了整个系统的控制逻辑,中介者除了能解耦并增加对象复用外,还有以下几点好处

控制逻辑集中,职责明确让模块更加方便维护

那么MVP的出现就是为了解决MVC各个层间的一个强耦合以及扩展不灵活等问题。所以在MVP中,P可以是设计成为一个接口,M和V也可以设计成一个接口,这才能发挥MVP价值最大化。

在使用MVP时,并不是都要接口化的,一定要按照实际情况去设计,如果真的只有存在一个实例,看似使用了MVP架构来做设计,但只是形似而已。这个时候要思考一下,项目是否到了需要考虑复用性和扩展性到的步了呢?还是,到不如把它们写成一团,反而少了一些不必要的类更易于阅读和维护。