笔记来源:尚硅谷Java设计模式(图解+框架源码剖析)

中介者模式

1、智能家庭管理问题

智能家庭项目:

  • 1)智能家庭包括各种设备,闹钟、咖啡机、电视机、窗帘等
  • 2)主人要看电视时,各个设备可以协同工作,自动完成看电视的准备工作,比如流程为:
    闹铃响起 => 咖啡机开始做咖啡 => 窗帘自动落下 => 电视机开始播放

image.png

传统方案解决智能家庭管理问题

image.png

传统方式问题分析

  • 1)当各电器对象有多种状态改变时,相互之间的调用关系会比较复杂
  • 2)各个电器对象彼此联系,你中有我,我中有你,不利于松耦合
  • 3)各个电器对象之间所传递的消息(参数),容易混乱
  • 4)当系统增加一个新的电器对象时,或者执行流程改变时,代码的可维护性、扩展性都不理想→考虑中介者模式

2、中介者模式

  • 1)中介者模式(Mediator Pattern),用一个中介对象来封装一系列的对象交互。中介者使各个对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互
  • 2)中介者模式属于行为型模式,使代码易于维护
  • 3)比如 MVC 模式,C(Controller控制器)是M(Model模型)和V(View视图)的中介者,在前后端交互时起到了中间人的作用

原理类图

image.png

中介者模式角色及职责

  • Mediator【抽象中介者】:定义了同事对象到中介者对象的接口
  • ConcreteMediator【具体的中介者对象】:实现抽象中介者方法,需要知道所有具体的同事类,即以一个集合来管理HashMap,并接受某个同事对象消息,完成相应的任务
  • Colleague【抽象同事类】
  • ConcreteColleague【具体的同事类】:会有很多,只知道自己的行为,而不了解其他同事类的行为(方法),但他们都依赖中介者对象

3、中介者模式解决智能家庭管理问题

UML 类图

image.png

image.png

智能家庭管理操作流程

  • 1)创建ConcreMediator对象
  • 2)创建各个同事类对象,比如:AlarmCoffeeMachineTV
  • 3)在创建同事类对象时,直接通过构造器加入到colleagueMap
  • 4)同事类对象可以调用sendMessage,最终会去调用ConcreteMediatorgetMessage方法
  • 5)getMessage会根据接收到的同事对象发出的消息,来协调调用其它的同事对象,完成任务
  • 6)可以看到getMessage是核心方法,完成相应任务

核心代码

抽象中介者

  1. public abstract class Mediator {
  2. public abstract void registerColleague(Colleague colleague);
  3. public abstract void getMsg(Integer state, String name);
  4. public abstract void sendMsg();
  5. }

抽象同事类

  1. public abstract class Colleague {
  2. private Mediator mediator;
  3. public Colleague(Mediator mediator) {
  4. this.mediator = mediator;
  5. }
  6. public Mediator getMediator() {
  7. return this.mediator;
  8. }
  9. public void sendMsg(Integer state) {
  10. this.getMediator().getMsg(state, this.getClass().getSimpleName());
  11. }
  12. }

具体同事类

  1. /**
  2. * 闹钟
  3. */
  4. public class Alarm extends Colleague {
  5. public Alarm(Mediator mediator) {
  6. super(mediator);
  7. this.getMediator().registerColleague(this);
  8. }
  9. /**
  10. * 闹铃响起
  11. */
  12. public void openAlarm() {
  13. System.out.println(">>>闹铃响起");
  14. try {
  15. //模拟闹铃耗时
  16. Thread.sleep(3000);
  17. } catch (InterruptedException e) {
  18. e.printStackTrace();
  19. }
  20. sendMsg(1);
  21. }
  22. /**
  23. * 闹铃关闭
  24. */
  25. public void closeAlarm() {
  26. System.out.println(">>>闹铃关闭");
  27. sendMsg(0);
  28. }
  29. }
  30. /**
  31. * 咖啡机
  32. */
  33. public class CoffeeMachine extends Colleague {
  34. public CoffeeMachine(Mediator mediator) {
  35. super(mediator);
  36. this.getMediator().registerColleague(this);
  37. }
  38. /**
  39. * 煮咖啡
  40. */
  41. public void makeCoffee() {
  42. System.out.println(">>>煮咖啡中...");
  43. sendMsg(0);
  44. try {
  45. //模拟煮咖啡耗时
  46. Thread.sleep(3000);
  47. } catch (InterruptedException e) {
  48. e.printStackTrace();
  49. }
  50. }
  51. /**
  52. * 煮咖啡完毕
  53. */
  54. public void completeCoffee() {
  55. System.out.println(">>>咖啡已煮好");
  56. sendMsg(1);
  57. }
  58. }
  59. /**
  60. * 窗帘
  61. */
  62. public class Curtain extends Colleague {
  63. public Curtain(Mediator mediator) {
  64. super(mediator);
  65. this.getMediator().registerColleague(this);
  66. }
  67. /**
  68. * 拉起窗帘
  69. */
  70. public void upCurtain() {
  71. System.out.println(">>>拉起窗帘...");
  72. sendMsg(1);
  73. try {
  74. //模拟拉起窗帘耗时
  75. Thread.sleep(3000);
  76. } catch (InterruptedException e) {
  77. e.printStackTrace();
  78. }
  79. }
  80. /**
  81. * 拉下窗帘
  82. */
  83. public void downCurtain() {
  84. System.out.println(">>>拉下窗帘...");
  85. sendMsg(0);
  86. try {
  87. //模拟拉下窗帘耗时
  88. Thread.sleep(3000);
  89. } catch (InterruptedException e) {
  90. e.printStackTrace();
  91. }
  92. }
  93. }
  94. /**
  95. * 电视机
  96. */
  97. public class TV extends Colleague {
  98. public TV(Mediator mediator) {
  99. super(mediator);
  100. this.getMediator().registerColleague(this);
  101. }
  102. /**
  103. * 打开电视
  104. */
  105. public void openTV() {
  106. System.out.println(">>>打开电视...");
  107. sendMsg(1);
  108. }
  109. /**
  110. * 关闭电视
  111. */
  112. public void closeTV() {
  113. System.out.println(">>>关闭电视...");
  114. sendMsg(0);
  115. }
  116. /**
  117. * 切换频道
  118. */
  119. public void switchChannel(Integer state) {
  120. System.out.println(">>>切换频道:" + state);
  121. sendMsg(state);
  122. try {
  123. //模拟看电视耗时
  124. Thread.sleep(3000);
  125. } catch (InterruptedException e) {
  126. e.printStackTrace();
  127. }
  128. }
  129. }

具体中介者

  1. public class ConcreteMediator extends Mediator {
  2. private Map<String, Colleague> colleagueMap;
  3. public ConcreteMediator() {
  4. this.colleagueMap = new HashMap<>();
  5. }
  6. @Override
  7. public void registerColleague(Colleague colleague) {
  8. colleagueMap.put(colleague.getClass().getSimpleName(), colleague);
  9. }
  10. @Override
  11. public void getMsg(Integer state, String name) {
  12. Colleague colleague = colleagueMap.get(name);
  13. if (colleague instanceof Alarm) {
  14. dealAlarm(state);
  15. } else if (colleague instanceof CoffeeMachine) {
  16. dealCoffeeMachine(state);
  17. } else if (colleague instanceof Curtain) {
  18. dealCurtain(state);
  19. } else if (colleague instanceof TV) {
  20. dealTV(state);
  21. }
  22. }
  23. /**
  24. * 闹铃响起后操作
  25. *
  26. * @param state
  27. */
  28. private void dealAlarm(Integer state) {
  29. if (Integer.valueOf(1).equals(state)) {
  30. ((Alarm) colleagueMap.get(Alarm.class.getSimpleName())).closeAlarm();
  31. ((CoffeeMachine) colleagueMap.get(CoffeeMachine.class.getSimpleName())).makeCoffee();
  32. }
  33. }
  34. /**
  35. * 咖啡机煮咖啡完毕后操作
  36. *
  37. * @param state
  38. */
  39. private void dealCoffeeMachine(Integer state) {
  40. if (Integer.valueOf(1).equals(state)) {
  41. ((Curtain) colleagueMap.get(Curtain.class.getSimpleName())).downCurtain();
  42. }
  43. }
  44. /**
  45. * 窗帘落下后操作
  46. *
  47. * @param state
  48. */
  49. private void dealCurtain(Integer state) {
  50. if (Integer.valueOf(0).equals(state)) {
  51. TV tv = (TV) colleagueMap.get(TV.class.getSimpleName());
  52. tv.openTV();
  53. tv.switchChannel(101);
  54. }
  55. }
  56. /**
  57. * 电视关闭后操作
  58. *
  59. * @param state
  60. */
  61. private void dealTV(Integer state) {
  62. if (Integer.valueOf(0).equals(state)) {
  63. ((Curtain) colleagueMap.get(Curtain.class.getSimpleName())).upCurtain();
  64. }
  65. }
  66. @Override
  67. public void sendMsg() {
  68. // Do Nothing...
  69. }
  70. }

测试代码

  1. //创建中介者
  2. Mediator mediator = new ConcreteMediator();
  3. //创建各个同事类,并加入Mediator中介者的Map对象中
  4. Alarm alarm = new Alarm(mediator);
  5. CoffeeMachine coffeeMachine = new CoffeeMachine(mediator);
  6. Curtain curtain = new Curtain(mediator);
  7. TV tv = new TV(mediator);
  8. //闹钟响起
  9. alarm.openAlarm();
  10. coffeeMachine.completeCoffee();
  11. tv.closeTV();
  12. //>>>闹铃响起
  13. //>>>闹铃关闭
  14. //>>>煮咖啡中...
  15. //>>>咖啡已煮好
  16. //>>>拉下窗帘...
  17. //>>>打开电视...
  18. //>>>切换频道:101
  19. //>>>关闭电视...
  20. //>>>拉起窗帘...

4、中介者模式的注意事项和细节

优点

  • 1)多个类相互耦合,会形成网状结构,使用中介者模式将网状结构分离为星型结构,进行解耦
  • 2)减少类间依赖,降低了耦合,符合迪米特原则

缺点

  • 3)中介者承担了较多的责任,一旦中介者出现了问题,整个系统就会受到影响
  • 4)如果设计不当,中介者对象本身变得过于复杂,这点在实际使用时,要特别注意