这个中介模式是我学习的时候最纠结的模式,它的字面意思很容易理解,就是把对象间复杂的交互封装起来,使对象间的耦合降低。但是多个对象间复杂的交互就一定会用到它吗,具体什么应用场景里才能合理的使用它呢?
我认为,交互的行为要稳定,即抽象中介类封装的接口要稳定,也就是说这些对象间交互的行为就那几个,不会太多,也不会变,甚至就一个,这样就可以对交互进行各种重写,实现多态。
举例,我比较喜欢我上一家公司的工作环境,个人认为明确的分工是高效开发的基础。上一家公司针对一个产品会形成一个部门,每个部门都不会太大,十多个人,都就叫xxx产品部,部门里有产品经理,需求,研发,测试,销售,技术支持,售后,这形成了一个小的产品开发生态环境,由于部门较小,所以产品经理不光负责产品规划,还负责部门内部的工作协调安排。如果没有产品经理,我需要接触认识需求、测试、技术支持、甚至售后,并且其他职位人员也需要接触认识部门的其他人,这对于老员工会好一些,但是对于一些需要协调的工作,或者对于新员工来说,产品经理的协调就会很有作用了。比如我需要需求提供下一个版本的产品需求,我不可能直接去找需求要,我要给经理发邮件,经理会先找销售确认客户是否有定制需求,然后找售后确认客户反馈,过滤后告诉需求人员这些并让其确认需求,并把需求转发给我。再比如,售后突然来找我说,哎呀,哥们,你的哪个哪个功能客户说用着不爽,你给改一下吧,那么对不起你去找经理,我手里有经理安排的正常的工作,改不改,怎么改,什么时候改,这些他要和经理确认,经理会让需求分析确认这些功能,可能还会征求测试和技术支持的意见,确认改动方案后再告诉我,我只需要改就好了,多么省心。如果我调到另外一个部门,我谁都不认识,但是我不用在乎这些,产品经理会给我安排工作,不用我重新调整和新员工的对接。这就是经理作为中介者所发挥的作用,他会简化我与其他同事的通信,并且对于索要需求,功能调整这样的复杂功能,产品经理会定制化(各种协调总结确认)这个功能,然后给我回复,这样每个职位的人员都只需要做好自己的工作,但是定制化交互行为就交给了中介者。
举例,我记得刚开始组装电脑的时候,网上买件,先确认cpu,然后找到和cpu接口匹配的主板,然后呢,就是各种配件,电源硬盘光驱内存条显卡机箱键盘鼠标显示器,所有的这些,只要能和主板接口匹配上,剩下的就是价钱了,越贵越好呗,这里的主板就是中介的角色,每种硬件设备都有自己的接口规范,所有硬件厂家都按照有限的这几套接口规范生产各种硬件,而主板就负责提供各种和硬件匹配的槽,把所有硬件连接到一起,实现基于硬件的系统和软件的运行,主板使得各个硬件复杂的连接交互都通过他们与主板的唯一接口传递,这样,过了三四年,我觉得i3处理器性能不好了,我再换一个i5就行了,其他的硬件都不用变,这就实现了硬件的复用。
我觉得我还是有必要实现一下非中介者模式下的产品部门内部日常工作流程,但是我只是想描述一下这种骚操作很乱,所以读者可以不看:
//研发
public class CommDeveloper {
public String getRequirement(CommAnalyst analyst,CommSalesman sale)
{
String req = analyst.analizeRequirement();
req += sale.customRequirement();
return "";
}
public boolean changeFunction()
{
return true;
}
}
//售后
public class CommAfterSales {
public boolean changeFunction(CommDeveloper dev,CommTechnician tech,CommAnalyst ana)
{
if(tech.changeFunction(10) == false)return false;
String req = ana.analizeRequirement();
if (req.isEmpty()) return false;
if(dev.changeFunction() == false)return false;
return true;
}
}
//需求
public class CommAnalyst {
public String analizeRequirement()
{
return "the requirement is aaa \n";
}
}
//销售
public class CommSalesman {
public String customRequirement()
{
return "the customed requirement is bbb \n";
}
}
//技术支持
public class CommSalesman {
public String customRequirement()
{
return "the customed requirement is bbb \n";
}
}
//应用场景
public static void main(String[] args) {
// TODO Auto-generated method stub
CommDeveloper dev = new CommDeveloper();
CommAfterSales afsales = new CommAfterSales();
CommAnalyst ana = new CommAnalyst();
CommSalesman sale = new CommSalesman();
CommTechnician tech = new CommTechnician();
String str = dev.getRequirement(ana, sale);
System.out.println(str);
afsales.changeFunction(dev, tech, ana);
}
妈个鸡儿,是不是很乱,如鲠在喉的说,当然这只是部分功能。这种紧耦合的东西,只要CommAnalyst 变了,那么我就要捋到CommDeveloper 并修改,照这么写,估计后来人会天天画圈感谢我,根据迪米特法则,不要和陌生人说话,看看上面,其实需求和销售对于研发人员来说,都应该是陌生人,但是咱们还不得不用。我们来看看我们的中介者模式:
中介者模式:用一个中介对象来封装一组对象的交互,使得它们不再显式的相互引用,从而实现每个对象的独立变化和复用,实现解耦。
一、特征
1、交互:中介者模式目标是对交互的封装,那么什么样的交互需要中介者封装呢?
第一,每个对象都有较好的封装,但是它们间的通信很复杂,当然把这些复杂的交互封装到每个对象类里就更不明智了,明明很好的封装会遭到破环。
第二,内部的交互行为需要定制化,也就是说某些交互行为需要在对这些对象类的功能复用的基础上还要做一些复杂的交互逻辑,我们可以基于对象类进行进一步派生来定制化交互,但是这样会产生很多子类,这时把这个定制化交互行为封装成中介者会更明知一些。
2、复用:因为对交互进行了封装并将交互行为进行了抽象,所以当交互行为发生变化时,别急,添加一个中介对象的实现就好了。
二、作用:
某些应用场景里,一组类存在复杂的交互拓扑,或者需要对交互进行进一步定制化。
三、实现:
看两个uml有啥不同,当交互的这组对象有相同的调用约定时,那调用约定就可以抽象到接口里,而下面的uml我认为是广义的中介者模式,每个对象的交互时的接口不同,就像我们上面产品部的例子。
我们来看看产品部如何用中介者模式实现:
//抽象中介类定义了交互行为
public abstract class Mediator {
abstract public boolean changeFunction();
abstract public String getRequirement();
}
//抽象同事类定义了对中介类的关联
public abstract class Colleague {
protected Mediator mediator;
Colleague(Mediator media)
{
mediator = media;
}
}
//具体研发者类
public class DeveloperColleague extends Colleague{
DeveloperColleague(Mediator media) {
super(media);
// TODO Auto-generated constructor stub
}
public String getRequirement()
{
return mediator.getRequirement();
}
public boolean changeFunction()
{
return true;
}
}
//具体需求类
public class AnalystColleague extends Colleague{
AnalystColleague(Mediator media) {
super(media);
// TODO Auto-generated constructor stub
}
public String analizeRequirement()
{
return "the requirement is aaa \n";
}
}
//具体售后类
public class AfterSalesColleague extends Colleague{
AfterSalesColleague(Mediator media) {
super(media);
// TODO Auto-generated constructor stub
}
public boolean changeFunction()
{
return super.mediator.changeFunction();
}
}
//具体销售类
public class SalesmanColleague extends Colleague{
SalesmanColleague(Mediator media) {
super(media);
// TODO Auto-generated constructor stub
}
public String customRequirement()
{
return "the customed requirement is bbb \n";
}
}
//具体技术支持类
public class TechnicianColleague extends Colleague{
TechnicianColleague(Mediator media) {
super(media);
// TODO Auto-generated constructor stub
}
public boolean changeFunction(int nFuncNum)
{
if(nFuncNum == 10)
{
return false;
}
return true;
}
}
//应用场景
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
ConcreteMediator mediator = new ConcreteMediator();
DeveloperColleague dev = new DeveloperColleague(mediator);
AfterSalesColleague afsales = new AfterSalesColleague(mediator);
AnalystColleague ana = new AnalystColleague(mediator);
SalesmanColleague sale = new SalesmanColleague(mediator);
TechnicianColleague tech = new TechnicianColleague(mediator);
mediator.setDev(dev);
mediator.setAfterSales(afsales);
mediator.setAna(ana);
mediator.setSalesman(sale);
mediator.setTech(tech);
System.out.println(dev.getRequirement());
afsales.changeFunction();
}
}
上面中介者模式的代码可以看出来应用场景里每个对象只与中介者交互,具体交互行为细节全部都封装在中介者里,这样就是先了对象组的解耦,但是可以发现中介者其实会很复杂,当中介者出现问题时,整个交互就会瘫痪,所以当应用场景中出现了一组对象复杂的交互方式时,先别着急用中介者模式,先静下来想想,是不是软件设计的就有问题。
参考:
https://blog.youkuaiyun.com/ztg1234/article/details/78359253