目录
- 一、场景
- 1、题目 【[来源](https://kamacoder.com/problempage.php?pid=1094)】
- 1.1 题目描述
- 1.2 输入描述
- 1.3 输出描述
- 1.4 输入示例
- 1.5 输出示例
- 二、不采用中介者设计模式
- 1 代码
- 2 问题
- 三、中介者设计模式
- 1 代码
- 2 更好的例子
- 四、个人思考
一、场景
- 设计模式不是银弹,而是特定场景的参考解法。
- 例如,在多人聊天室场景下,不采用中介者模式,系统会变得复杂。
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;}@Overridepublic void receive(String message) {System.out.println(name + " received: " + message);}@Overridepublic 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<>();}@Overridepublic 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按钮的状态,这就需要中介者模式来处理了。
- 多选框会影响Select All、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 {...
}