设计模式 ( 十九) 中介者模式

目录 

一、定义

二、未使用/使用中介者模式对比

三、角色分析

四、中介者模式案例分析

五、总结


一、定义

中介者模式,其实就是定义了一个具体中介者对象来协调各个子系统的交互依赖关系,使得各个子系统之间不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式属于行为型模式。

在现实生活中,有很多中介者模式的身影,例如QQ游戏平台,聊天室、QQ群、短信平台和房产中介。我们使用的QQ聊天室和短信平台其实就是充当了一个中介者角色,通过这个平台我们就可以与其他QQ用户进行聊天或者发短信,并不需要依赖其他用户。还有就是我们熟悉的MVC三层架构中: Controller控制层就是Model模型层和View视图层之间的中介者。

二、未使用/使用中介者模式对比

  • 如果不使用中介者模式,让各个子系统之间相互发生依赖关系的话,那么系统耦合性会比较大, 也不利于系统维护以及开发人员的理解;
  • 使用中介者模式之后,将这些依赖关系断开,引入一个中介者用于协调他们之间的关系,让各个子系统只与中介者发生依赖,三个对象A、B、C都相互都不依赖;

三、角色分析

中介者模式的通用类图如下所示:

下面我们分析一下中介者模式涉及的几个角色:

  • 抽象中介者角色:提供了同事对象注册与转发同事对象信息的抽象方法,用于各同事对象之间的交互;
  • 具体中介者角色:实现了抽象中介角色定义的抽象方法,一般聚合了所有的具体同事类,负责协调各同事对象的行为以完成协作;
  • 抽象同事角色:抽象同事类,定义了具体同事角色共同的行为;
  • 具体同事角色:一般会有多个具体同事角色,每个具体同事角色都只知道和中介者角色发生依赖,并不知道其他同事角色的行为方法;

四、中介者模式案例分析

我们使用生活中必不可少的QQ聊天程序作为中介者模式讲解的示例,这里的“中介者”其实就是 QQ 服务器,而我们这些各个用户其实就是具体同事类。类图如下:

首先定义我们的抽象中介者角色,它定义了同事对象到中介者对象的接口,具体代码如下:

public abstract class Mediator {

    /**
     * 注册同事方法
     */
    public abstract void register(String key, Colleague colleague);

    /**
     * 发送消息
     */
    public abstract void sendMessage(String key);

}

抽象中介者提供了两个方法:

  • 注册同事方法;
  • 发送消息方法;

下面我们定义抽象同事类角色,它主要定义了具体同事角色共同的行为,即发送消息、接收消息,把它类比成聊天的我们,那么我们肯定也就是拥有发送消息、接收消息的行为:

public abstract class Colleague {

    /**
     * 发送消息
     */
    public abstract void sendMessage();

    /**
     * 接收消息
     */
    public abstract void receiveMessage();

}

下面我们定义两个使用QQ服务器的角色:UserA和UserB,它们充当具体同事类的角色,具体代码如下:

public class QQUserA extends Colleague {
    private static final String USER_A_REGISTER_KEY = "userA";
    private static final String USER_B_REGISTER_KEY = "userB";
    /**
     * 持有一个抽象中介者对象引用
     */
    private Mediator mediator;

    public QQUserA(Mediator mediator) {
        this.mediator = mediator;
        //注册到中介中容器中
        mediator.register(USER_A_REGISTER_KEY, this);
    }

    @Override
    public void sendMessage() {
        System.out.println("用户A发出消息...");
        //UserA发送消息的时候,通过中介者发送消息,实际上调用的是UserB的接收消息方法
        mediator.sendMessage(USER_B_REGISTER_KEY);
    }

    @Override
    public void receiveMessage() {
        System.out.println("用户A接收到消息...");
    }
}


public class QQUserB extends Colleague {
    /**
     * 持有一个抽象中介者对象引用
     */
    private Mediator mediator;
    private static final String USER_A_REGISTER_KEY = "userA";
    private static final String USER_B_REGISTER_KEY = "userB";

    public QQUserB(Mediator mediator) {
        this.mediator = mediator;
        //注册到中介中容器中
        mediator.register(USER_B_REGISTER_KEY, this);
    }

    @Override
    public void sendMessage() {
        System.out.println("用户B发出消息...");
        //UserB发送消息的时候,通过中介者发送消息,实际上调用的是UserA的接收消息方法
        mediator.sendMessage(USER_A_REGISTER_KEY);
    }

    @Override
    public void receiveMessage() {
        System.out.println("用户B接收到消息...");
    }
}

可以看到,我们的具体同事类都持有一个抽象中介者对象引用,并在发送完消息后,通过中介者角色调用另外一个用户的接收消息方法,实现了两个用户之间的通信。

当然,抽象中介者的引用也可以放在父类-抽象同事类中。

下面还差一个具体的中介者对象,也就是我们前面提到的QQ聊天服务器,具体代码如下:

public class QQServer extends Mediator {

    /**
     * 具体中介者类持有多个同事类对象引用
     * 这里使用Map保存,当然也可以使用List或者其他集合进行保存
     */
    private Map<String, Colleague> colleagueMap = new HashMap<>();

    @Override
    public void register(String key, Colleague colleague) {
        colleagueMap.put(key, colleague);
    }

    @Override
    public void sendMessage(String key) {
        Colleague colleague = colleagueMap.get(key);
        if (null != colleague) {
            colleague.receiveMessage();
        }
    }
}

具体中介者内部使用一个容器,可以是List,也可以是Map或者其他容器,用于存放所有的具体同事类的引用,在前面的具体同事类的构造方法中,在创建具体同事类的时候,就会将他们注册到中介者的容器里面,并且具体的中介者【QQ聊天服务器】提供了一个转发消息的方法sendMessage(),实际上就是调用具体同事类的接收消息方法,完成消息的转发。

最后,我们看下客户端怎么调用:

public class Client {
    public static void main(String[] args) {
        Mediator qqServer = new QQServer();
        Colleague userA = new QQUserA(qqServer);
        Colleague userB = new QQUserB(qqServer);
        //用户A发出消息
        userA.sendMessage();

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

        //用户B发出消息
        userB.sendMessage();
    }
}

运行结果如下:

 

可以看到,通过具体中介者对象【QQ聊天服务器】,解耦了各个同事类【UserA、UserB...】之间相互依赖的场景,具体同事类直接都与中介者对象发生关联。

五、总结

中介者模式的优点:

  • 降低了对象之间的耦合性,使得对象易于独立地被复用;
  • 将对象间的一对多关联转变为一对一的关联,提高系统的灵活性,使得系统易于维护和扩展;
  • 符合迪米特原则;

中介者模式的缺点:

  • 具体中介者角色承担了较多的职责,一旦出现了问题,整个系统将会受到比较大的影响;
  • 具体的中介者比较庞大,难以维护;
  • 新增加一个同事类时,不得不去修改抽象中介者类和具体中介者类,此时可以使用观察者模式和状态模式来解决这个问题;

中介者模式的适用场景:

  • 当对象之间存在复杂的网状结构关系而导致依赖关系混乱且难以复用时,可以考虑使用中介者模式;
  • 当想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类时,可以考虑使用中介者模式;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值