个人Java设计模式-中介者模式

本篇文章已受权微信公众号 guolin_blog (郭霖)独家发布git

小时候钟爱战争片,《地道战》、《鸡毛信》、《铁道游击队》一系列的老电影,咦~想起都激动得起鸡皮疙瘩。不过以为特别逗的是,电影里面总会有“这里是xxx,咱们被包围了,请求支援请求支援”这么一句台词。github

来分析一下这句台词怎么来的。假设有N多个战区,战区的分布错综复杂,不少时候一个战区的丢失会影响整个战争局势。因此这就得要有一个司令部指挥和协调各个战区,而一旦战区被攻打,报告司令部请求支援,司令部则调度其余战区进行协助。设计模式

那在咱们的程序设计中有没有这样的模式?有的,中介者模式应运而生,目的就是处理这样的情景问题。微信

1、中介者模式

定义

  中介者封装一系列对象相互做用,使得这些对象耦合松散,而且能够独立的改变它们之间的交互。dom

UML

中介者模式UML图

中介者模式涉及到的角色有四个:优化

- 抽象中介者角色:抽象中介者角色定义统一的接口,以及一个或者多个事件方法,用于各同事角色之间的通讯。this

- 具体中介者角色:实现了抽象中介者所声明的事件方法,协调各同事类之间的行为,持有全部同事类对象的引用。spa

- 抽象同事类角色:定义了抽象同事类,持有抽象中介者对象的引用。设计

- 具体同事类角色:继承抽象同事类,实现本身业务,经过中介者跟其余同事类进行通讯。code

2、中介者模式实战

假设这样的一个情景。有A、B、C三个战区,A被敌方攻打,请求B支援。可是此时B也被敌方攻打,因此A继续向C请求支援,这么巧C此时正在支援B。情景比较简单,咱们的例子也围绕着这个情景来展开,首先来看不使用中介者模式是怎么实现的。

A战区代码以下:

public class SituationA {
    // 请求支援
    public void requestSupport(String situation) {
        System.out.println(getClass().getSimpleName() + ":这里是A战区,如今被敌方攻打,请求" + situation + "支援");
    }
}

SituationA定义了请求支援的方法,向其余战区请求支援。再来看B战区的代码定义:

public class SituationB {
    // 请求支援
    public void requestSupport(String situation) {
        System.out.println(getClass().getSimpleName() + ":这里是B战区,如今被敌方攻打,请求" + situation + "支援");
    }

    // 是否支援
    public void support(boolean isSupport) {
        if (isSupport) {
            System.out.println(getClass().getSimpleName() + ":Copy that,还有五秒钟到达战场");
        } else {
            System.out.println(getClass().getSimpleName() + ":支援你妹,我也正在被攻打");
        }
    }
}

SituationB也定义了请求支援的方法,还多了根据isSupport是否支援其余战区的方法。还有SituationC,SituationC和SituationB代码差很少,直接贴出来了,很少作解释。

public class SituationC {
    // 请求支援
    public void requestSupport(String situation) {
        System.out.println(getClass().getSimpleName() + ":这里是B战区,如今被敌方攻打,请求" + situation + "支援");
    }

    // 是否支援
    public void support(boolean isSupport) {
        if (isSupport) {
            System.out.println(getClass().getSimpleName() + ":Copy that,还有五秒钟到达战场");
        } else {
            System.out.println(getClass().getSimpleName() + ":很差意思,来迟一步了,正在前往别的战区支援");
        }
    }
}

OK,三个类都定义好了,咱们根据情景看看客户端是怎样运行的,代码以下:

public class Client {
    public static void main(String[] args) {
        System.out.println("-------A被攻打,请求B支援--------");
        SituationA situationA = new SituationA();
        situationA.requestSupport("B");
        System.out.println("-------B也正在被攻打--------");
        SituationB situationB = new SituationB();
        situationB.support(false);
        System.out.println("-------A又向C请求支援--------");
        situationA.requestSupport("C");
        System.out.println("-------C很忙--------");
        SituationC situationC = new SituationC();
        situationC.support(false);
    }
}

运行结果以下:

-------A被攻打,请求B支援--------
SituationA:这里是A战区,如今被敌方攻打,请求B支援
-------B也正在被攻打--------
SituationB:支援你妹,我也正在被攻打
-------A又向C请求支援--------
SituationA:这里是A战区,如今被敌方攻打,请求C支援
-------C很忙--------
SituationC:很差意思,来迟一步了,正在前往别的战区支援

回到咱们的场景当中,A、B、C是相互两两关联的,而且关联的两个类与其余类是不能协调通讯。所以,在实际中,战区类增多,它们之间的耦合度越高,这样首先会形成当一个类修改了,其余类也要跟着须要修改,而后就是多个类之间的通讯变得复杂混乱。就跟咱们上面列子同样,A、B、C相互支援,A并不知道C已经支援B了。由于这些缘由,在代码设计中加入中介者角色,每一个类都通过中介者进行沟通和协调。

下面来看中介者模式的实现,首先定义抽象中介者角色类,代码以下:

public abstract class Mediator {
    protected SituationA situationA;
    protected SituationB situationB;
    protected SituationC situationC;

    Mediator() {
        situationA = new SituationA(this);
        situationB = new SituationB(this);
        situationC = new SituationC(this);
    }

    /**
     * 事件的业务流程处理
     *
     * @param method
     */
    public abstract void execute(String method);
}

抽象中介者类主要定义了同事类的事件业务流程方法,而且持有每个具体同事类的引用,再来看具体中介者的实现:

public class Command extends Mediator {

    public void execute(String method) {
        if (method.equals("aRequestSupport")) {
            this.aRequestSupport();
        } else if (method.equals("bRequestSupport")) {
            this.bRequestSupport();
        }
    }

    // A请求支援
    private void aRequestSupport() {
        System.out.println("SituationA:这里是A战区,如今被敌方攻打,请求支援");
        boolean isBSupport = isSupport();  // B是否能够支援
        super.situationB.bSupport(isBSupport);
        if (!isBSupport) { // B支援不了,请求C
            System.out.println("-------A又向C请求支援--------");
            boolean isASupport = isSupport();  // B是否能够支援
            super.situationC.cSupport(isASupport);
            if (!isASupport) {
                System.out.println("-------本身看着办吧。--------");
            }
        }
    }

    // B请求支援
    public void bRequestSupport() {
        System.out.println("这里是B的请求支援");
    }

    private boolean isSupport() {
        Random rand = new Random();
        return rand.nextBoolean();
    }
}

代码比较长,但也比较简单。定义了处理各个对象关系的业务方法,把依赖关系转移到了这个业务方法中,而同事类只须要委托中介者协调各个同事类的业务逻辑。

public abstract class Colleague {
    protected Mediator mediator;

    public Colleague(Mediator mediator) {
        this.mediator = mediator;
    }
}

很简单的就一个构造方法,继续看具体同事类的实现,我先把各个同事类的代码都贴出来:

// A战区
public class SituationA extends Colleague {

    public SituationA(Mediator mediator) {
        super(mediator);
    }

    // 请求支援
    public void aRequestSupport() {
        super.mediator.execute("aRequestSupport");
    }
}

// B战区
public class SituationB extends Colleague {

    public SituationB(Mediator mediator) {
        super(mediator);
    }

    // 请求支援
    public void bRequestSupport() {
        super.mediator.execute("bRequestSupport");
    }

    public void bSupport(boolean isSupport) {
        if (isSupport) {
            System.out.println("SituationB:Copy that,还有五秒钟到达战场");
        } else {
            System.out.println("-------B也正在被攻打--------");
            System.out.println("SituationB:支援你妹,我也正在被攻打");
        }
    }
}

// C战区
public class SituationC extends Colleague {
    public SituationC(Mediator mediator) {
        super(mediator);
    }

    // 请求支援
    public void cRequestSupport() {
        super.mediator.execute("cRequestSupport");
    }

    public void cSupport(boolean isSupport) {
        if (isSupport) {
            System.out.println(getClass().getSimpleName() + ":Copy that,还有五秒钟到达战场");
        } else {
            System.out.println(getClass().getSimpleName() + ":很差意思,来迟一步了,正在前往别的战区支援");
        }
    }
}

跟前面说的同样,经过cRequestSupport方法中的execute委托中介者处理同事类的业务逻辑,自己只负责处理自身的业务。

最后来看客户端的实现,代码以下:

public class Client {
    public static void main(String[] args) {
        Mediator mediator = new Command();
        System.out.println("-------A被攻打,请求支援--------");
        SituationA situationA = new SituationA(mediator);
        situationA.aRequestSupport();
    }
}

能够看到,表面上请求仍是从A发出,可是A已经委托了中介者进行业务逻辑和流程的处理。这样的好处就是每一个同事类的职责都很清晰,跟其余同事类有关联的都委托到中介者,自己专一本身的行为。

运行客户端,结果以下:

-------A被攻打,请求支援--------
SituationA:这里是A战区,如今被敌方攻打,请求支援
-------B也正在被攻打--------
SituationB:支援你妹,我也正在被攻打
-------A又向C请求支援--------
SituationC:Copy that,还有五秒钟到达战场

3、中介者模式的优缺点

优势

1)解耦。把同事类原来一对多的依赖变成一对一的依赖,下降同事类的耦合度,同时也符合了迪米特原则。

缺点

1)中介者模式把业务流程和协调都写在中介者,当同事类越多,中介者的业务就越复杂,形成很差管理的弊端。

2)中介者模式还有一个明显的缺点,若是要增减同事类,必须得修改抽象中介者角色和具体中介者角色类。

4、模式扩展

中介者模式和观察者模式混编

为何要跟观察者模式组合混编?首先,上面提到了若是要增长或者删除同事类,必须对中介者这个角色进行修改,由于中介者角色的业务逻辑相对比较集中和复杂,修改中介者角色会比较麻烦。另一点是,使用观察者模式实现同事类(被观察者)的通讯能够优化中介者的业务逻辑流程,避免过多使用if...else。

同事类通知->中介者协调处理->中介者通知同事类

其实能够说成中介者模式是经过观察者模式实现的,都是事件驱动模型。这里简单阐述下原理,把中介者做为观察者,即中介者角色实现Observer接口,重写update方法(重点就在update,同事类跟中介者,中介者月同事类之间的通讯就在这实现)。同事类继承Observable被观察者类,经过notifyObservers能够与中介者通讯。这样就在至关于观察者模式的基础上(观察者模式的交互路径较短),在中介者中增长了消息转发的功能,也就是说同事类之间的通讯通过了中介者。

中介者模式VS门面模式

先简单介绍下门面模式。要求一个子系统的外部与其内部的通讯必须经过一个统一的对象进行,这就是门面模式。门面模式主要的是提供了一个高层次的接口,也就是所谓的一个统一对象,经过它跟子系统进行通讯。这样作的好处就是,第一,外部与系统内部解耦,减小相互之间的依赖;第二,增长系统内部的灵活性,系统内部变化不影响外部跟门面角色的关系。好比拍照,能够用手机拍,也能够用单反相机拍,把手机和单反封装在一块儿,外部只能看到一个摄像头,你只能说拍照,里面究竟是手机拍仍是单反拍是不知道的。

中介者模式和门面模式一样的都是经过封装一个角色来进行隔离解耦,但中介者强调的是中介协调同事类之间的通讯,门面模式则是经过门面对内部进行隔离。另外,中介者模式的通讯是双向的,而门面模式的通讯是单向的。

总结

系统中多个对象之间相互依赖,而且依赖关系结构复杂致使对象之间的耦合度增大,修改难度大,这个时候能够考虑使用中介者模式来梳理对象之间的通讯,达到下降对象之间耦合度的效果。中介者模式就到这,下一篇命令模式,您的点赞和关注是个人动力,钦敬钦敬!

设计模式Java源码GitHub下载https://github.com/jetLee92/DesignPattern

更多干货关注微信公众号“Jet啟思”

AndroidJet的开发之路

相关文章
相关标签/搜索