整个团队的交流过程如果变成了为了组员向仲裁者报告,仲裁者向组员下达指令。组员之间不再相互询问和互相指示。Mediator的意思就是“仲裁者”、“中介者”。一方面,当发生麻烦事情的时候,通知仲裁者;当发生涉及全体组员的事情的时候,也通知仲裁者。当仲裁者下达指令时,组员会立即执行。团队组员之间不再相互沟通并私自做出决定,而是发生任何事情都向仲裁者报告。另一方面,仲裁者站在整个团队的角度上对组员上报的事情做出决定。这就是Mediator模式。

示例程序:

对于一个简单的登录对话框,使用方法如下:

  • 可以选择作为作为游客登录或作为用户登录。
  • 作为用户登录时,需要输入正确的用户名和密码。
  • 点击ok按钮可以登录,点击Cancel按钮可以取消登录

但其实里面的逻辑还是比较复杂的:

  • 如果选择作为游客访问,那么禁用用户名输入框和密码输入框,使用户无法输入。
  • 如果选择走位用户访问,那么启用用户名输入框和密码输入框,使用户可以输入。
  • 如果在用户名输入框中一个字符都没有输入,那么禁用密码输入框,使用户无法输入密码。
  • 如果在用户名输入框中输入了至少一个字符,那么启用密码输入框,使用户可以输入密码。
  • 只有当用户名输入框和密码输入框中都至少输入一个字符后,ok按钮才处于启动状态,可以被按下。用户名输入框或密码输入框中一个字符都没有被输入的时候,禁用ok按钮,使其不可被按下。
  • Cancel按钮总是处于启用状态,任何时候都可以按下该按钮。

对话框中的单选按钮、文本输入框、确认或者取消按钮都是单独的类。如果将上面的逻辑处理分散在个各类中,那么编码的工作量会变得非常大。这是因为所有的对象都是相互制约、相互关联的。

类和接口的一览表:

名字 说明
Mediator 定义“仲裁者”的接口(API)的接口
Colleague 定义“组员”的接口(API)的接口
ColleagueButton 表现按钮的类。它实现了Colleague接口
ColleagueTextField 表示文本输入框的类。它实现了Colleague接口
ColleagueCheckbox 表示勾选框的类,它实现了Colleague接口
LoginFrame 表示登录对话框的类,它实现了Mediator接口
Maiin 测试程序行为的类

Mediator接口:

  1. public interface Mediator {
  2. public abstract void creatColleague(); // 用于生成对话框的按钮和文本输入框等控件
  3. public abstract void colleagueChanged(); // 会被各个Colleague组员调用。它的作用是让组员可以向仲裁者进行报告
  4. }

Colleague接口:

是表示向仲裁者进行报告的组员安的接口。具体的组员会实现这个接口。

  1. public interface Colleague {
  2. public abstract void setMediator(Mediator mediator); // 告知组员我是仲裁者,向该方法中传递的参数是仲裁者的实例对象
  3. public abstract void setColleagueEnabled(boolean enabled); // 告诉组员仲裁者下达的指示。
  4. // 参数enabled如果为true,就表示为自己需要变为"启动状态",这个方法表明,到底是启用还是禁用,并非
  5. // 由组员自己决定,而是由仲裁者决定
  6. }

ColleagueButton类:
控制按钮的启用/关闭状态。

  1. public class ColleagueButton extends Button implements Colleague {
  2. private Mediator mediator;
  3. public ColleagueButton(String caption) {
  4. super(caption);
  5. }
  6. @Override
  7. public void setMediator(Mediator mediator) { // 保存Mediator
  8. this.mediator = mediator;
  9. }
  10. @Override
  11. public void setColleagueEnabled(boolean enabled) { // Mediator下达启用/禁用的命令
  12. setEnabled(enabled);
  13. }
  14. }

ColleagueTextField:

  1. public class ColleagueTextField extends TextField implements TextListener,Colleague {
  2. private Mediator mediator;
  3. public ColleagueTextField(String text,int columns){
  4. super(text,columns);
  5. }
  6. @Override
  7. public void setMediator(Mediator mediator) {
  8. this.mediator = mediator;
  9. }
  10. @Override
  11. public void setColleagueEnabled(boolean enabled) {
  12. setEnabled(true);
  13. setBackground(enabled ? Color.white : Color.lightGray);
  14. }
  15. @Override
  16. public void textValueChanged(TextEvent e) {
  17. mediator.colleagueChanged(); // 当文字发生变化时通知Mediator
  18. }
  19. }

ColleagueCheckbox类:

  1. public class ColleagueCheckbox extends Checkbox implements ItemListener,Colleague {
  2. private Mediator mediator;
  3. public ColleagueCheckbox(String label, boolean state, CheckboxGroup group) throws HeadlessException {
  4. super(label, state, group); // 构造函数
  5. }
  6. @Override
  7. public void setMediator(Mediator mediator) { // 保存mediator
  8. this.mediator = mediator;
  9. }
  10. @Override
  11. public void setColleagueEnabled(boolean enabled) { // mediator下达启用/ 禁用指示
  12. setEnabled(enabled);
  13. }
  14. @Override
  15. public void itemStateChanged(ItemEvent e) {
  16. mediator.colleagueChanged(); // 当状态发生变化时通知mediator
  17. }
  18. }

LoginFrame:

最终所有的决定都是由仲裁者的colleagueChanged下达的。

  1. public class LoginFrame extends Frame implements ActionListener, Mediator {
  2. private ColleagueCheckbox checkGuest;
  3. private ColleagueCheckbox checkLogin;
  4. private ColleagueTextField textUser;
  5. private ColleagueTextField textPass;
  6. private ColleagueButton buttonOk;
  7. private ColleagueButton buttonCancel;
  8. // 构造函数
  9. // 生成并配置各个Colleague后,显示对话框
  10. public LoginFrame(String title) {
  11. super(title);
  12. setBackground(Color.lightGray);
  13. // 使用布局管理器生成4*2窗格
  14. setLayout(new GridLayout(4, 2));
  15. // 生成各个Colleague
  16. creatColleague();
  17. // 配置
  18. add(checkGuest);
  19. add(checkLogin);
  20. add(new Label("Username:"));
  21. add(textUser);
  22. add(new Label("Password:"));
  23. add(textPass);
  24. add(buttonOk);
  25. add(buttonCancel);
  26. // 设置初始的启用 / 禁用状态
  27. colleagueChanged();
  28. // 显示
  29. pack();
  30. show();
  31. }
  32. // 生成各个Colleague
  33. @Override
  34. public void creatColleague() {
  35. // 生成
  36. CheckboxGroup g = new CheckboxGroup();
  37. checkGuest = new ColleagueCheckbox("Guest", true, g);
  38. checkLogin = new ColleagueCheckbox("Login", false, g);
  39. textUser = new ColleagueTextField("", 10);
  40. textPass = new ColleagueTextField("", 10);
  41. textPass.setEchoChar('*');
  42. buttonOk = new ColleagueButton("OK");
  43. buttonCancel = new ColleagueButton("Cancel");
  44. // 设置Mediator
  45. checkGuest.setMediator(this);
  46. checkLogin.setMediator(this);
  47. textUser.setMediator(this);
  48. textPass.setMediator(this);
  49. buttonOk.setMediator(this);
  50. buttonCancel.setMediator(this);
  51. // 设置Listener
  52. checkGuest.addItemListener(checkGuest);
  53. checkLogin.addItemListener(checkLogin);
  54. textUser.addTextListener(textUser);
  55. textPass.addTextListener(textPass);
  56. buttonOk.addActionListener(this);
  57. buttonCancel.addActionListener(this);
  58. }
  59. // 接收来自于colleague的通知然后判断各Colleague的启用/禁用状态
  60. @Override
  61. public void colleagueChanged() {
  62. if (checkGuest.getState()) {
  63. textUser.setColleagueEnabled(false);
  64. textPass.setColleagueEnabled(false);
  65. buttonOk.setEnabled(true);
  66. } else {
  67. textUser.setColleagueEnabled(true);
  68. }
  69. }
  70. // 当textUser或textPass文本输入框中的文字发生变化时
  71. // 判断各College的启用 / 禁用状态
  72. private void userPassChanged() {
  73. if (textUser.getText().length() > 0) {
  74. textPass.setColleagueEnabled(true);
  75. if (textPass.getText().length() > 0) {
  76. buttonOk.setColleagueEnabled(true);
  77. } else {
  78. buttonOk.setColleagueEnabled(false);
  79. }
  80. } else {
  81. textPass.setColleagueEnabled(false);
  82. textPass.setColleagueEnabled(false);
  83. }
  84. }
  85. @Override
  86. public void actionPerformed(ActionEvent e) {
  87. System.out.println(e.toString());
  88. System.exit(0);
  89. }
  90. }

Mediator模式中的登场角色:

Mediator(仲裁者、中介者):

负责定义与Colleague角色进行通信和做出决定的接口(API)。在示例程序中,由Mediator接口扮演此角色。

ConcreteMediator(具体的仲裁者、中介者):

负责实现Mediator角色的接口(API),负责实际做出决定。

Colleague(同事):

负责定义与Mediaator角色进行通信的接口。

ConcreteColleague(具体的同事):

负责实现Colleague角色的接口。