深入浅出学设计模式(七)之中介者模式

今天我们一起学习一下中介者模式。该模式在实际开发中用的可能不是很多,我们主要学习该模式的思想,一般可以用在类似于调度中心、多个模块之间频繁的进行互相调用时,我们就可以考虑使用中介者模式,就比如我们以前在学习 jsp 的时候,不能直接在一个 jsp 中请求另一个 jsp,而是需要在两个 jsp 之间添加一个 controller 控制器,这样就避免了 jsp 的代码臃肿难维护、混乱的问题。

1 中介者模式概述

1.1 定义

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

该定义不难理解,就是说多个对象之间的相互调用会使系统的耦合性增加,我们用一个中介对象来将这些对象的行为进行封装,即由中介者对象来决定什么时候调用哪个对象的哪个方法,而不是这些对象之间的互相调用,这些对象本身就只关心自己应该完成的功能,而不用关心怎样调用别的对象的方法。

举个生活中的例子:我们在看电影《中国机长》的时候,大家应该都有体会到机场塔台的作用,假如机场没有塔台,当刘机长准备降落成都时,他就要关心自己现在是否可以降落,前方是否有跑道可以降落,这些问题都需要他来联系别的机长才能得到答案,在那千钧一发之际,如果这样的话后果可能就会很严重了。所以,这些问题不能够由各个机长来沟通决定。而是由塔台这个中介者来负责调度,机长只需要听从塔台的安排即可。

到这里我们也不难发现中介者模式的优点了,该模式可以把互相耦合的对象进行解耦,使网状结构分散成星型结构
在这里插入图片描述
上图就展示了网状结构,我们可以看到各个模块之间的调用是非常混乱的,各个模块相互依赖,如果一个模块要做出修改,他将影响到其他模块。
在这里插入图片描述
该图展示了星型结构,我们可以看出模块之间的依赖关系已经不存在了,每个模块只需要与中间的中介者进行相互依赖即可。

2 UML 图

2.1 UML 图

在这里插入图片描述

中介者模式有如下几个角色:

Mediator :抽象中介者角色,主要定义一个接口,用于各个同事之间进行互相通信。与同事类相互依赖。

ConcreteMediator:具体的中介者角色,Mediator 的具体实现,将同事之间的相互依赖关系转移到自己中。

Colleague:抽象的同事类,也叫抽象组件,以前互相依赖的各个对象或组件,互相之间以“同事” 称呼。主要定义一些各个具体同事类之间共有的方法。

ConcreteColleague:具体的同事类,Colleague 的具体实现类当一个同事类想要调用另一个同事的方法的时候,它必须调用中介者的方法,中介者中的方法再去调用其他同事的方法。

由于 ConcreteMediator 与 ConcreteColleague 需要互相通信,所以在 ConcreteMediator 中需要聚合所有的 ConcreteColleague ,所有的 ConcreteColleague 需要聚合 ConcreteMediator 。为了 UML 图看起来简单,我只在 Mediator 和 Colleague 之间使用了 双向关联关系来体现双向的聚合关系。

掌握中介者模式的精髓在于在同事类自己的方法中,如果要调用其他同事的方法,不管三七二十一,只管调用中介者提供的方法即可,自己唯一要做的是:如何与中介者沟通。中介者中的方法将多个同事的不同方法根据业务需求封装到一起。

2.2 简单示例

那么接下来,我们使用代码来具体描述一下:

Colleague.java:抽象同事类

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

    public Mediator getMediator() {
        return mediator;
    }

    public abstract void methodA();
    public abstract void methodB();
}

ConcreteColleagueA:具体的抽象类

public class ConcreteColleagueA extends Colleague {
    public ConcreteColleagueA(Mediator mediator) {
        super(mediator);
        mediator.setColleagueA(this);
    }

    @Override
    public void methodA() {
        System.out.println("ConcreteColleagueA methodA()");
        //通过中介者来调用其他同事类的方法
        super.getMediator().dealSomething("colleagueA");
    }

    @Override
    public void methodB() {
        System.out.println("ConcreteColleagueA methodB()");
    }

    public void methodC() {
        System.out.println("ConcreteColleagueA methodC()");
    }
}

ConcreteColleagueB.java:

public class ConcreteColleagueB extends Colleague {
    public ConcreteColleagueB(Mediator mediator) {
        super(mediator);
        mediator.setColleagueB(this);
    }

    @Override
    public void methodA() {
        System.out.println("ConcreteColleagueB methodA()");
    }

    @Override
    public void methodB() {
        System.out.println("ConcreteColleagueB methodB()");
        super.getMediator().dealSomething("colleagueB");
    }
}

Mediator.java:抽象的中介者类

public abstract class Mediator {
    private ConcreteColleagueA colleagueA;
    private ConcreteColleagueB colleagueB;

    //与同事类进行通信的方法
    //
    public abstract void dealSomething(String message);

    public ConcreteColleagueA getColleagueA() {
        return colleagueA;
    }

    public void setColleagueA(ConcreteColleagueA colleagueA) {
        this.colleagueA = colleagueA;
    }

    public ConcreteColleagueB getColleagueB() {
        return colleagueB;
    }

    public void setColleagueB(ConcreteColleagueB colleagueB) {
        this.colleagueB = colleagueB;
    }
}

ConcreteMediator.java:具体的中介者类

public class ConcreteMediator extends Mediator {

	/**
     * @param message:中介者收到什么样的 消息 就进行相应的处理
     * 与同事类中调用该方法是传入的值要匹配
     */
    @Override
    public void dealSomething(String message) {
        if("colleagueA".equals(message)){
            super.getColleagueB().methodA();
        }else if("colleagueB".equals(message)){
            super.getColleagueA().methodC();
            super.getColleagueA().methodB();
            super.getColleagueA().methodA();
        }
    }
}

Client.java:测试类:

public class Client {
    public static void main(String[] args) {
        Mediator mediator = new ConcreteMediator();

        ConcreteColleagueA colleagueA = new ConcreteColleagueA(mediator);
        ConcreteColleagueB colleagueB = new ConcreteColleagueB(mediator);

        colleagueA.methodA();//1
        //colleagueB.methodB();//2
    }
}

[1] 在测试代码中,注释掉第二行代码(//2 处代码),结果如下:
在这里插入图片描述
结果如我们所料,先执行了 ConcreteColleagueA 的 methodA() 方法,再执行 ConcreteColleagueB 的 methodA() 方法。在 ConcreteColleagueA 的 methodA() 通过中介者对象来调用 ConcreteColleagueB 的 methodA() 方法。如果我们不使用中介者模式的话,可能就会出现如下代码:

@Override
    public void methodA() {
        System.out.println("ConcreteColleagueA methodA()");
        colleagueB.methodA();//对 colleagueB 进行了强依赖
    }

[2] 在测试代码中,注释掉第一行代码(** //1处代码** ),结果如下:
在这里插入图片描述
在调用 ConcreteColleagueB 的 methodB() 方法时,会通过中介者来调用 ConcreteColleagueA 的 methodC()、methodB()、methodA() 方法,当调用到 methodA() 方法时,又会通过中介者调用 ConcreteColleagueB 的 methodA() 方法。所以在使用中介者模式时,一定要注意:不要出现循环调用。

3 实际案例

需求:现有两个类 A 和 B ,各自都维护一个数字 num ,无论怎样修改 A 或 B 中的数字,A 中的数字始终都是 B 中的 10 倍。

该示例引用自 23种设计模式(7):中介者模式 。

public abstract class Colleague {
    private Mediator mediator;
    private int num ;
    public Colleague(Mediator mediator){
        this.mediator = mediator;
    }

    public Mediator getMediator() {
        return mediator;
    }

    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }
    public void changeNum(int num){
        this.num = num;
    }
}
public class ColleagueA extends Colleague {
    public ColleagueA(Mediator mediator) {
        super(mediator);
        mediator.setColleagueA(this);
    }

    @Override
    public void setNum(int num) {
        super.setNum(num);
        //A 设置完自己的数字后,去修改 B 中的数字
        //通过中介者来修改 B 中的数字
        super.getMediator().AChangeB();
    }
}
public class ColleagueB extends Colleague {
    public ColleagueB(Mediator mediator) {
        super(mediator);
        mediator.setColleagueB(this);
    }

    @Override
    public void setNum(int num) {
        super.setNum(num);
        //B 设置完自己的数字后,去修改 A 中的数字
        //通过中介者来修改 A 中的数字
        super.getMediator().BChangeA();
    }
}
public abstract class Mediator {
    private ColleagueA colleagueA;
    private ColleagueB colleagueB;

    public ColleagueA getColleagueA() {
        return colleagueA;
    }

    public void setColleagueA(ColleagueA colleagueA) {
        this.colleagueA = colleagueA;
    }

    public ColleagueB getColleagueB() {
        return colleagueB;
    }

    public void setColleagueB(ColleagueB colleagueB) {
        this.colleagueB = colleagueB;
    }

    //同事 A 改变 同事 B 中的数字
    public abstract void AChangeB();

    //同事 B 改变 同事 A 中的数字
    public abstract void BChangeA();
}
public class ConcreteMediator extends Mediator {
    @Override
    public void AChangeB() {
        //将 A 中的数字 除以 10 赋值给 B
        int num = super.getColleagueA().getNum();
        super.getColleagueB().changeNum( num /10 );
    }

    @Override
    public void BChangeA() {
        //将 B 中的数字 乘以 10 赋值给 A
        int num = super.getColleagueB().getNum();
        super.getColleagueA().changeNum( num *10 );
    }
}
public class Client {
    public static void main(String[] args) {
        Mediator mediator = new ConcreteMediator();

        ColleagueA colleagueA = new ColleagueA(mediator);
        ColleagueB colleagueB = new ColleagueB(mediator);

        System.out.println("设置 A 中的数字:100");
        colleagueA.setNum(100);
        System.out.println("A 中的数字:"+colleagueA.getNum());
        System.out.println("B 中的数字:"+colleagueB.getNum());

        System.out.println("*****************");

        System.out.println("设置 B 中的数字:100");
        colleagueB.setNum(100);
        System.out.println("A 中的数字:"+colleagueA.getNum());
        System.out.println("B 中的数字:"+colleagueB.getNum());
    }
}

运行结果截图:
在这里插入图片描述

4 总结

首先,我们先总结一下中介者模式的优缺点:

优点:

  • 使得多个同事类之间的相互依赖得到解耦,使得某一个同事类只关心自己的业务,想要使用别的同事的方法时,只需要与中介者通信即可。

缺点:

  • 中介者模式容易出现循环调用的问题,编写代码时需要格外小心。
  • 中介者对象容易变得很大,其中的代码会变得臃肿。

最后,我们来讨论一下 中介者与同事类之间通信的方式:本文通过两个示例代码展示了两种通信方式。第一种:同事类与中介者类通过 message 消息来识别同事类需要中介者完成什么样的功能;第二种:则是直接调用中介者中不同的方法来完成不同的功能。对于这两种方式,个人推荐使用第一种,当有新的同事类增加时,不需要新增方法,而是在 if else 代码中新增一个分支。

5 示例代码

示例代码地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值