设计模式之中介者模式

Posted 泡^泡

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之中介者模式相关的知识,希望对你有一定的参考价值。

什么是中介者模式

定义:
用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。属于行为型模式。

何时使用
多个类相互耦合,形成了网状结构。

如何解决:
将上述网状结构分离为星型结构。

应用实例:
1、中国加入 WTO 之前是各个国家相互贸易,结构复杂,现在是各个国家通过 WTO 来互相贸易。
2、机场调度系统。
3、MVC 框架,其中C(控制器)就是 M(模型)和 V(视图)的中介者。

优点:
1、降低了类的复杂度,将一对多转化成了一对一。
2、各个类之间的解耦。
3、符合迪米特原则。

缺点:
中介者会庞大,变得复杂难以维护。

使用场景:
1、系统中对象之间存在比较复杂的引用关系,导致它们之间的依赖关系结构混乱而且难以复用该对象。
2、想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。

UML:

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

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

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

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

  • 具体同事类角色:继承抽象同事类,实现自己业务,通过中介者跟其他同事类进行通信。

二、中介者模式实战

代码案例

假设这样的一个情景。有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() + ":不好意思,来迟一步了,正在前往别的战区支援");
        
    

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

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请求支援--------
SituationCCopy that,还有五秒钟到达战场

源码地址

https://gitee.com/myzjspace/design-pattern

以上是关于设计模式之中介者模式的主要内容,如果未能解决你的问题,请参考以下文章

java设计模式之中介者模式

设计模式之中介者模式20170731

设计模式之中介模式

设计模式——行为型模式之中介者模式

设计模式之中介者模式

设计模式之行为型中介模式