我所理解的设计模式系列·第22篇·基于中介者模式实现聊天服务器

2022/02/22 设计模式 共 2651 字,约 8 分钟

中介者模式(Mediator pattern)顾名思义,就是充当了中介的角色,中介就是架起了消费者与开发商之间的桥梁,消费者无需知道开发商具体是谁,开发商也无须知道消费者具体是谁,他们都通过中介者来完成交易。

事实上,我们日常网上冲浪用到最多的微信也是如此。当我和朋友聊天的时候,严格意义上来说,我并不是和朋友在聊天,而是我将消息发送到聊天服务器这个“中介者”身上,然后聊天服务器将消息再转发给我的朋友。在这个过程中,我和我的朋友既是消息的发送者,也是消息的接收者。

design-patttern-22-中介者模式-封面

1. 定义

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

2. 类图

在中介者模式中,有这样几种角色:

  • 抽象中介者(Mediator):抽象中介者角色提供了同事角色的注册与响应方法,用于同事角色间的通信
  • 具体中介者(Concrete Mediator):抽象中介者的实现类,聚合了一个列表来存储注册的同事类并对其进行管理
  • 抽象同事类(Colleague):抽象同事角色会依赖抽象者角色,因为它会给予抽象者角色与其他同事角色进行通信,同时它会提供所有同事类的公有操作
  • 具体同事类(Concrete Colleague):抽象同事类的实现类,实现了具体与其他同事角色的通信逻辑

中介者模式的类图如下:

design-patttern-22-中介者模式-1-类图

3. 示例

今天就以一个简单的聊天服务器来介绍中介者模式,这里有两类角色,一个是聊天服务器,一个是用户,前者自然是中介者角色,那么后者就是同事角色。

下面来进行编码,首先定义同事角色,代码如下:

public class User {
    // 用户昵称
    private String username;
    // 用户群组
    private String group;
    // 用户所属聊天服务器
    private ChatServer chatServer;

    public User(String username, String group) {
        this.username = username;
        this.group = group;
    }

    // 接收消息
    public void receive(Message message) {
        System.out.println("用户" + this.username + "收到用户" + message.getSender().getUsername() + "发来的消息,内容为:" + message.getContent());
    }

    // 发送消息
    public void send(Message message) {
        System.out.println("用户" + this.username + "向群组" + this.group + "的用户发出消息,内容为:" + message.getContent());
        chatServer.reply(message);
    }

    // 省略 setter/getter 方法
}

同事角色有两个方法,一个是主动向中介者——聊天服务器发送消息的 send 方法;另一个是接收聊天服务器传递过来的信息的 receive 方法。

然后定义中介者角色,代码如下:

public class ChatServer {

    private List<User> users = new ArrayList<>();

    public void register(User user) {
        users.add(user);
        user.setChatServer(this);
        System.out.println("用户" + user.getUsername() + "加入聊天室");
    }

    public void reply(Message message) {
        for (User user1:users) {
            if (message.getTargetGroup().equals(user1.getGroup())) {
                user1.receive(message);
            }
        }
    }
}

中介者角色会维护一个同事角色的列表,提供注册同事类方法和发送消息方法。

这里需要做一个消息体的抽象,代码如下所示:

public class Message {
    // 发送内容
    private String content;
    // 发送组
    private String targetGroup;
    // 发送者
    private User sender;

    public Message(String content, String targetGroup, User sender) {
        this.content = content;
        this.targetGroup = targetGroup;
        this.sender = sender;
    }

    // 省略 setter/getter 方法
}

最后编写测试代码:

public class Test {
    public static void main(String[] args) {
        ChatServer chatServer = new ChatServer();
        User user1 = new User("user1", "A");
        User user2 = new User("user2", "A");
        User user3 = new User("user3", "B");
        chatServer.register(user1);
        chatServer.register(user2);
        chatServer.register(user3);

        Message message = new Message("你好", "A", user3);
        user3.send(message);
    }
}

输出结果为:

用户user1加入聊天室
用户user2加入聊天室
用户user3加入聊天室
用户user3向群组B的用户发出消息,内容为:你好
用户user1收到用户user3发来的消息,内容为:你好
用户user2收到用户user3发来的消息,内容为:你好

4. 使用场景

中介者模式的使用场景是:

  • 在对象关系的类图中出现了复杂的网状结构时,可以考虑使用中介者模式

5. 小结

本文讲述了中介者模式,它的定义是——用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

中介者模式的优点是:

  • 减少类与类之间的依赖与耦合度,如可以将原本一对多的关系优化为一对一,让系统变得易于维护

中介者模式的缺点是:

  • 当同事类有很多时,中介者角色会变得十分复杂,难以维护

6. 参考资料

最后,本文收录于个人语雀知识库: 我所理解的后端技术,欢迎来访。

文档信息

Search

    Table of Contents