对中介者模式的理解

一、场景

  • 设计模式不是银弹,而是特定场景的参考解法。
  • 例如,在多人聊天室场景下,不采用中介者模式,系统会变得复杂。

1、题目 【来源

1.1 题目描述

小明正在设计一个简单的多人聊天室系统,有多个用户和一个聊天室中介者,用户通过中介者进行聊天,请你帮他完成这个系统的设计。

1.2 输入描述

第一行包括一个整数N,表示用户的数量(1 <= N <= 100) 第二行是N个用户,比如User1 User2 User3,用空格分隔 第三行开始,每行包含两个字符串,表示消息的发出者和消息内容,用空格分隔

1.3 输出描述

对于每个用户,输出一行,包含该用户收到的所有消息内容。

1.4 输入示例

3
User1 User2 User3
User1 Hello_All!
User2 Hi_User1!
User3 How_is_everyone?

1.5 输出示例

User2 received: Hello_All!
User3 received: Hello_All!
User1 received: Hi_User1!
User3 received: Hi_User1!
User1 received: How_is_everyone?
User2 received: How_is_everyone?

二、不采用中介者设计模式

1 代码

  • 将聊天室的人定义为User:
public class User {
    private List<User> friends;
    private String name;

    public User(String name) {
        this.name = name;
        friends = new ArrayList<>();
    }

    public void addFriend(User user) {
        friends.add(user);
    }

    public void sendMessage(String message) {
        friends.forEach(user -> user.receiveMessage(message));
    }

    private void receiveMessage(String message) {
        System.out.println(name + " received: " + message);
    }
}
  • 客户端:
public class Application {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Map<String, User> userMap = new TreeMap<>();

        int n = scanner.nextInt();
        for (int i = 0; i < n; i++) {
            String name = scanner.next();
            User user = new User(name);
            userMap.put(name, user);
        }

        List<User> users = new ArrayList<>(userMap.values());
        users.stream().forEach(user -> {
            for (User friend : users) {
                if (!user.equals(friend)) {
                    user.addFriend(friend);
                }
            }
        });

        for (int i = 0; i < n; i++) {
            String name = scanner.next();
            String message = scanner.next();
            userMap.get(name).sendMessage(message);
        }

    }
}

2 问题

  • 现在聊天室里就3个人,只要1个人发消息,其他人都能收到。如果有人退群了,或者有新朋友加群了,都需要重新维护关系:
List<User> users = new ArrayList<>(userMap.values());
users.stream().forEach(user -> {
    for (User friend : users) {
        if (!user.equals(friend)) {
            user.addFriend(friend);
        }
    }
});
  • 当一个实体(例如:User)状态变化时,会影响其他实体,不应该由实体本身来维护这种复杂关系。实体只需关心自己的状态变化即可。
    • 这就需要中介者设计模式。

三、中介者设计模式

1 代码

  • 用户:
public interface Colleague {
    void receive(String message);
    String gotName();
}

public class User implements Colleague {
    private final String name;

    public User(String name) {
        this.name = name;
    }

    @Override
    public void receive(String message) {
        System.out.println(name + " received: " + message);
    }

    @Override
    public String gotName() {
        return name;
    }
}
  • 中介者:
public interface Mediator {
    void add(Colleague colleague);
}

public class ChatRoom implements Mediator {
    private List<Colleague> colleagues;

    public ChatRoom() {
        this.colleagues = new ArrayList<>();
    }

    @Override
    public void add(Colleague colleague) {
        colleagues.add(colleague);
    }

    public void send(String message, Colleague colleague) {
        colleagues.stream()
                .filter(c -> !StringUtils.equals(c.gotName(), colleague.gotName()))
                .forEach(c -> c.receive(message));
    }
}
  • 客户端:
public class Application {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        ChatRoom chatRoom = new ChatRoom();

        int n = scanner.nextInt();
        for (int i = 0; i < n; i++) {
            String name = scanner.next();
            chatRoom.add(new User(name));

        }

        for (int i = 0; i < n; i++) {
            String name = scanner.next();
            String message = scanner.next();
            chatRoom.send(message, new User(name));
        }
    }
}

2 更好的例子

  • 廖雪峰老师在介绍中介者模式时,举的例子更好:
    在这里插入图片描述
    • 多选框会影响Select All、Select None的按钮状态。
      • 例如,多选框勾选后,Select None按钮便会亮起: 在这里插入图片描述
    • 多选框不应该去关心Select None按钮的状态,这就需要中介者模式来处理了。
  • 多选框状态变化后,中介者“收到变化消息”,如果需要更改按钮的状态,则去更改状态。
  • 代码:
public class Mediator {
    // 引用UI组件:
    private List<JCheckBox> checkBoxList;
    private JButton selectAll;
    private JButton selectNone;
    private JButton selectInverse;

    public Mediator(List<JCheckBox> checkBoxList, JButton selectAll, JButton selectNone, JButton selectInverse) {
        ......
        // 绑定事件:
        this.checkBoxList.forEach(checkBox -> {
            checkBox.addChangeListener(this::onCheckBoxChanged);
        });
        this.selectAll.addActionListener(this::onSelectAllClicked);
        this.selectNone.addActionListener(this::onSelectNoneClicked);
        this.selectInverse.addActionListener(this::onSelectInverseClicked);
    }

    // 当checkbox有变化时:
    public void onCheckBoxChanged(ChangeEvent event) {
        boolean allChecked = true;
        boolean allUnchecked = true;
        for (JCheckBox checkBox : checkBoxList) {
            if (checkBox.isSelected()) {
                allUnchecked = false;
            } else {
                allChecked = false;
            }
        }
        selectAll.setEnabled(!allChecked);
        selectNone.setEnabled(!allUnchecked);
    }

    // 当点击select all:
    public void onSelectAllClicked(ActionEvent event) {
        checkBoxList.forEach(checkBox -> checkBox.setSelected(true));
        selectAll.setEnabled(false);
        selectNone.setEnabled(true);
    }

    // 当点击select none:
    public void onSelectNoneClicked(ActionEvent event) {
        checkBoxList.forEach(checkBox -> checkBox.setSelected(false));
        selectAll.setEnabled(true);
        selectNone.setEnabled(false);
    }

    // 当点击select inverse:
    public void onSelectInverseClicked(ActionEvent event) {
        checkBoxList.forEach(checkBox -> checkBox.setSelected(!checkBox.isSelected()));
        onCheckBoxChanged(null);
    }
}

四、个人思考

  • 当我们对场景建模后发现,实体们呈现类似如下关系时:
    在这里插入图片描述
    • 我们就需要引入中介来统筹实体们的相互影响。
      • 实体1变化了,发消息给中介,中介收到后,去改变实体4和实体2的状态。
  • 中介者:
public interface Mediator {
	...
}

public class xxx implements Mediator {
	...
}
  • 各种实体:
public interface Colleague {
    ...
}

public class yyy implements Colleague {
	...
}

相关推荐

  1. 建造模式理解

    2024-05-14 07:34:14       10 阅读
  2. 观察模式理解

    2024-05-14 07:34:14       8 阅读
  3. 适配器模式理解

    2024-05-14 07:34:14       8 阅读
  4. 原型模式理解

    2024-05-14 07:34:14       11 阅读
  5. 外观模式理解

    2024-05-14 07:34:14       4 阅读
  6. 策略模式理解

    2024-05-14 07:34:14       6 阅读

最近更新

  1. .Net Core WebAPI参数的传递方式

    2024-05-14 07:34:14       2 阅读
  2. QT--气泡框的实现

    2024-05-14 07:34:14       3 阅读
  3. LeetCode 968.监控二叉树 (hard)

    2024-05-14 07:34:14       2 阅读
  4. leetcode热题100.完全平方数(动态规划进阶)

    2024-05-14 07:34:14       2 阅读
  5. leetcode328-Odd Even Linked List

    2024-05-14 07:34:14       3 阅读
  6. C 语言设计模式(结构型)

    2024-05-14 07:34:14       2 阅读
  7. v-if 与 v-show(vue3条件渲染)

    2024-05-14 07:34:14       2 阅读
  8. kafka防止消息丢失配置

    2024-05-14 07:34:14       3 阅读

热门阅读

  1. k8s 服务发现

    2024-05-14 07:34:14       4 阅读
  2. react之Reducer和Context的联合使用

    2024-05-14 07:34:14       4 阅读
  3. Python 中的 heapq 模块简介

    2024-05-14 07:34:14       5 阅读
  4. 项目总结(后面应该怎做)

    2024-05-14 07:34:14       3 阅读