[关闭]
@w1992wishes 2018-03-13T14:12:07.000000Z 字数 11045 阅读 995

设计模式--中介者模式

设计模式 行为型模式


目录

本文的结构如下:

一、引言

日常开发是离不开电脑的,这需要cpu、内存、显卡、键盘、显示器等零件相互调用,如果直接让这些零件互相调用,它们之间的关系会很复杂:

显然这样造成的后果是难以维护,为了避免这种情况,开发商引入了主板,由主板和各部件进行交互,统一协调,这样每个部件只需要把命令传给主板,由主板决定同哪个部件交互,然后接受主板返回的数据即可,不需要知道其他部件的存在:

在软件开发中,面向对象设计鼓励将行为分布到各个对象中。这种分布可能会导致对象间有许多连接。在最坏的情况下,每一个对象都知道其他所有对象。

将一个系统分割成许多对象通常可以增强可复用性,但是对象间相互连接的激增又会降低其可复用性。大量的相互连接使得一个对象似乎不太可能在没有其他对象的支持下工作—--系统表现为一个不可分割的整体(过度耦合)。而且对系统的行为进行任何较大的改动都十分困难。

这时可以像电脑开发商一样引入“主板”来解决,这就是中介者模式。

二、什么是中介者模式

如果在一个系统中对象之间存在多对多的相互关系(像没有引入主板前电脑各部件,它们被称为“同事类”),这时可以将对象之间的一些交互行为从各个对象中分离出来,并集中封装在一个中介者对象中,并由该中介者进行统一协调,这样对象之间多对多的复杂关系就转化为相对简单的一对多关系。通过引入中介者来简化对象之间的复杂交互,中介者模式是“迪米特法则”的一个典型应用。

中介者模式定义如下:

中介者模式(Mediator Pattern):用一个中介对象(中介者)来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式。

中介者模式解决的困境就是多个对象之间的相互引用导致的紧耦合,通过引入一个中介者,原来互相引用的对象就相互解耦了,他们之间现在没有任何关系,只和中介者交互。

说白了中介者模式把对象之间的多对多关系转换成了同中介者类的一对多关系,从而降低耦合。

三、模式的结构

中介者模式UML类图如下:

中介者模式将一个网状的系统结构变成一个以中介者对象为中心的星形结构,在这个星型结构中,使用中介者对象与其他对象的一对多关系来取代原有对象之间的多对多关系。在中介者模式结构图中包含如下几个角色:

中介者模式的核心是中介者类,它承担了两方面的职责:

  1. 中转作用(结构性):通过中介者提供的中转作用,各个同事对象就不再需要显式引用其他同事,当需要和其他同事进行通信时,可通过中介者来实现间接调用。该中转作用属于中介者在结构上的支持。
  2. 协调作用(行为性):中介者可以更进一步的对同事之间的关系进行封装,同事可以一致的和中介者进行交互,而不需要指明中介者需要具体怎么做,中介者根据封装在自身内部的协调逻辑,对同事的请求进行进一步处理,将同事成员之间的关系行为进行分离和封装。该协调作用属于中介者在行为上的支持。

四、典型代码

抽象中介者类典型代码如下:

  1. public abstract class Mediator {
  2. public abstract void Send(String message, Colleague colleague);
  3. }

具体中介者典型代码如下:

  1. public class ConcreteMediator extends Mediator{
  2. private ConcreteColleague1 colleague1;
  3. private ConcreteColleague2 colleague2;
  4. public void setColleague1(ConcreteColleague1 colleague1) {
  5. this.colleague1 = colleague1;
  6. }
  7. public void setColleague2(ConcreteColleague2 colleague2) {
  8. this.colleague2 = colleague2;
  9. }
  10. public void Send(String message, Colleague colleague) {
  11. if (colleague == colleague1) {
  12. colleague2.Notify(message);
  13. } else if (colleague == colleague2){
  14. colleague1.Notify(message);
  15. } else {
  16. System.out.println("Error!");
  17. }
  18. }
  19. }

抽象同事类典型代码:

  1. public abstract class Colleague {
  2. protected Mediator mediator;
  3. public Colleague(Mediator mediator) {
  4. this.mediator = mediator;
  5. }
  6. public void Send(String message) {
  7. mediator.Send(message, this);
  8. }
  9. public abstract void Notify(String message);
  10. }

具体同事类典型代码:

  1. public class ConcreteColleague1 extends Colleague{
  2. public ConcreteColleague1(Mediator mediator) {
  3. super(mediator);
  4. }
  5. public void Notify(String message) {
  6. System.out.println("同事1得到信息:" + message);
  7. }
  8. }
  9. public class ConcreteColleague2 extends Colleague{
  10. public ConcreteColleague2(Mediator mediator) {
  11. super(mediator);
  12. }
  13. public void Notify(String message) {
  14. System.out.println("同事2得到信息:" + message);
  15. }
  16. }

客户端测试:

  1. public class MediatorPatternDemo {
  2. public static void main(String[] args) {
  3. ConcreteMediator mediator = new ConcreteMediator();
  4. ConcreteColleague1 colleague1 = new ConcreteColleague1(mediator);
  5. ConcreteColleague2 colleague2 = new ConcreteColleague2(mediator);
  6. mediator.setColleague1(colleague1);
  7. mediator.setColleague2(colleague2);
  8. colleague1.Send("How are you?");
  9. colleague2.Send("Fine, thank you. And you?");
  10. colleague1.Send("I'm fine. Thankes.");
  11. }
  12. }

五、代码示例

5.1、标准中介者模式

假设使用电脑播放视频,把步骤分为如下几步:

  1. 光驱读取光盘内容,把读取到的内容传递给主板。
  2. 主板得到内容,交给cpu处理。
  3. cpu处理完毕,把处理后的数据传递给主板。
  4. 主板把数据传递给显卡,显卡显示视频(忽略了显示器显示这个步骤)。

不使用中介者模式


  1. public class CDDriver{
  2. private String data;
  3. private CPU cpu;
  4. public CDDriver(){
  5. this.cpu = new CPU();
  6. }
  7. public String getData() {
  8. return data;
  9. }
  10. public void readCD(){
  11. //逗号前是视频数据,逗号后是音频数据
  12. this.data = "Video Data,Sound Data";
  13. //然后CPU处理
  14. cpu.executeData(data);
  15. }
  16. }
  17. public class CPU{
  18. private VideoCard videoCard;
  19. private SoundCard soundCard;
  20. public CPU() {
  21. videoCard = new VideoCard();
  22. soundCard = new SoundCard();
  23. }
  24. public void executeData(String data){
  25. //分解数据,前面是视频数据,后面是音频数据
  26. String[] ss = data.split(",");
  27. String videoData = ss[0];
  28. String soundData = ss[1];
  29. videoCard.showData(videoData);
  30. soundCard.soundData(soundData);
  31. }
  32. }
  33. public class VideoCard{
  34. public void showData(String data){
  35. System.out.println("你正在观看的是:" + data);
  36. }
  37. }
  38. public class SoundCard{
  39. public void soundData(String data){
  40. System.out.println("你听到的声音是:" + data);
  41. }
  42. }

这里设计的关联其实还算简单,并没有很复杂,但仍然会发现有以下问题:


使用中介者模式


抽象中介者:

  1. public interface Mediator {
  2. void changed(Colleague colleague);
  3. }

具体中介者主板类:

  1. public class MainBoard implements Mediator {
  2. private CDDriver cdDriver;
  3. private CPU cpu;
  4. private VideoCard videoCard;
  5. private SoundCard soundCard;
  6. public void changed(Colleague colleague) {
  7. if(colleague == cdDriver){
  8. //表示光驱读取了数据
  9. this.operateCDDriverReadData((CDDriver)colleague);
  10. }else if(colleague == cpu){
  11. //表示CPU处理完数据
  12. this.operateCPU((CPU)colleague);
  13. }
  14. }
  15. public void setCdDriver(CDDriver cdDriver) {
  16. this.cdDriver = cdDriver;
  17. }
  18. public void setCpu(CPU cpu) {
  19. this.cpu = cpu;
  20. }
  21. public void setVideoCard(VideoCard videoCard) {
  22. this.videoCard = videoCard;
  23. }
  24. public void setSoundCard(SoundCard soundCard) {
  25. this.soundCard = soundCard;
  26. }
  27. public void operateCDDriverReadData(CDDriver cd){
  28. String data = cd.getData();
  29. this.cpu.executeData(data);
  30. }
  31. public void operateCPU(CPU cpu){
  32. String videoData = cpu.getVideoData();
  33. String soundData = cpu.getSoundData();
  34. this.videoCard.showData(videoData);
  35. this.soundCard.soundData(soundData);
  36. }
  37. }

抽象同事类:

  1. public abstract class Colleague {
  2. private final Mediator mediator;
  3. public Colleague(Mediator mediator){
  4. this.mediator = mediator;
  5. }
  6. public Mediator getMediator(){
  7. return mediator;
  8. }
  9. }

具体同事类:

  1. public class CDDriver extends Colleague {
  2. private String data;
  3. public CDDriver(Mediator mediator) {
  4. super(mediator);
  5. }
  6. public String getData() {
  7. return data;
  8. }
  9. public void readCD(){
  10. //逗号前是视频数据,逗号后是音频数据
  11. this.data = "Video Data,Sound Data";
  12. //通知主板,自己的状态发生了变化
  13. this.getMediator().changed(this);
  14. }
  15. }
  16. public class CPU extends Colleague {
  17. private String videoData;
  18. private String soundData;
  19. public CPU(Mediator mediator) {
  20. super(mediator);
  21. }
  22. public String getVideoData() {
  23. return videoData;
  24. }
  25. public String getSoundData() {
  26. return soundData;
  27. }
  28. public void executeData(String data){
  29. //分解数据,前面是视频数据,后面是音频数据
  30. String[] ss = data.split(",");
  31. this.videoData = ss[0];
  32. this.soundData = ss[1];
  33. //通知主板,CPU的工作完成
  34. this.getMediator().changed(this);
  35. }
  36. }
  37. public class VideoCard extends Colleague{
  38. public VideoCard(Mediator mediator) {
  39. super(mediator);
  40. }
  41. public void showData(String data){
  42. System.out.println("你正在观看的是:" + data);
  43. }
  44. }
  45. public class SoundCard extends Colleague {
  46. public SoundCard(Mediator mediator) {
  47. super(mediator);
  48. }
  49. public void soundData(String data){
  50. System.out.println("你听到的声音是:" + data);
  51. }
  52. }

客户端测试:

  1. public class MediatorPatternDemo {
  2. public static void main(String[] args) {
  3. MainBoard mediator = new MainBoard();
  4. CDDriver cd = new CDDriver(mediator);
  5. CPU cpu = new CPU(mediator);
  6. VideoCard vc = new VideoCard(mediator);
  7. SoundCard sc = new SoundCard(mediator);
  8. mediator.setCdDriver(cd);
  9. mediator.setCpu(cpu);
  10. mediator.setVideoCard(vc);
  11. mediator.setSoundCard(sc);
  12. cd.readCD();
  13. }
  14. }

引入中介者类后,再来看就会发现组件之间不再相互关联,系统之间耦合度降低,更易复用,扩展和维护,当然会发现系统相关变得复杂。

5.2、更广义的中介者模式

我们知道现实开发中,很多时候不会完全符合标准中介者模式,这时可以实际情况做一些变化,比如:

现假设有有小说类和类别类,为此制定了一个书单,书单上有平时追更的小说,当小说完结了,也就追更完毕,就把小说从书单删除;还有可以将冷门类别的小说从书单删除......

这样实现:

  1. public class Novel {
  2. private String novelId;
  3. private String novelName;
  4. private boolean finsh;
  5. public Novel(String novelId, String novelName){
  6. this.novelId = novelId;
  7. this.novelName = novelName;
  8. }
  9. public String getNovelId() {
  10. return novelId;
  11. }
  12. public String getNovelName() {
  13. return novelName;
  14. }
  15. public void setNovelId(String novelId) {
  16. this.novelId = novelId;
  17. }
  18. public void setNovelName(String novelName) {
  19. this.novelName = novelName;
  20. }
  21. public boolean isFinsh() {
  22. return finsh;
  23. }
  24. public void setFinsh(boolean finsh) {
  25. //如果完结了,就从书单删除
  26. if (finsh){
  27. NovelTypeMediator mediator = NovelTypeMediator.getInstance();
  28. mediator.removeNovel(novelId);
  29. }
  30. this.finsh = finsh;
  31. }
  32. }
  33. public class Type {
  34. private String typeId;
  35. private String typeName;
  36. private boolean unpopular;
  37. public Type(String typeId, String typeName) {
  38. this.typeId = typeId;
  39. this.typeName = typeName;
  40. }
  41. public void setTypeId(String typeId) {
  42. this.typeId = typeId;
  43. }
  44. public void setTypeName(String typeName) {
  45. this.typeName = typeName;
  46. }
  47. public String getTypeId() {
  48. return typeId;
  49. }
  50. public String getTypeName() {
  51. return typeName;
  52. }
  53. public boolean isUnpopular() {
  54. return unpopular;
  55. }
  56. public void setUnpopular(boolean unpopular) {
  57. if (unpopular){
  58. NovelTypeMediator mediator = NovelTypeMediator.getInstance();
  59. mediator.removeType(typeId);
  60. }
  61. this.unpopular = unpopular;
  62. }
  63. }
  64. public class NovelTypeRelation {
  65. private String id;
  66. private String novelId;
  67. private String typeId;
  68. public NovelTypeRelation(String id, String novelId, String typeId) {
  69. this.id = id;
  70. this.novelId = novelId;
  71. this.typeId = typeId;
  72. }
  73. public String getId() {
  74. return id;
  75. }
  76. public String getNovelId() {
  77. return novelId;
  78. }
  79. public String getTypeId() {
  80. return typeId;
  81. }
  82. public void setId(String id) {
  83. this.id = id;
  84. }
  85. public void setNovelId(String novelId) {
  86. this.novelId = novelId;
  87. }
  88. public void setTypeId(String typeId) {
  89. this.typeId = typeId;
  90. }
  91. }
  92. public class NovelTypeMediator {
  93. private static NovelTypeMediator instance = new NovelTypeMediator();
  94. //书单
  95. private List<NovelTypeRelation> novelList = new ArrayList<NovelTypeRelation>();
  96. public static NovelTypeMediator getInstance(){
  97. return instance;
  98. }
  99. private NovelTypeMediator(){
  100. initData();
  101. }
  102. private void initData() {
  103. NovelTypeRelation n1 = new NovelTypeRelation("1", "1n", "1t");
  104. NovelTypeRelation n2 = new NovelTypeRelation("2", "2n", "1t");
  105. NovelTypeRelation n3 = new NovelTypeRelation("3", "3n", "2t");
  106. NovelTypeRelation n4 = new NovelTypeRelation("4", "4n", "2t");
  107. novelList.add(n1);
  108. novelList.add(n2);
  109. novelList.add(n3);
  110. novelList.add(n4);
  111. }
  112. /**
  113. * 展示书单
  114. */
  115. public void showNovelList(){
  116. for (NovelTypeRelation relation : novelList){
  117. System.out.println("小说编号是:" + relation.getNovelId() + ", 类型编号是:" + relation.getTypeId());
  118. }
  119. }
  120. /**
  121. * 删除小说
  122. * @param novelId
  123. */
  124. public void removeNovel(String novelId){
  125. for (Iterator<NovelTypeRelation> itr = novelList.iterator(); itr.hasNext();){
  126. NovelTypeRelation relation = itr.next();
  127. if (relation.getNovelId().equals(novelId)){
  128. itr.remove();
  129. }
  130. }
  131. }
  132. /**
  133. * 删除类型
  134. * @param typeId
  135. */
  136. public void removeType(String typeId){
  137. for (Iterator<NovelTypeRelation> itr = novelList.iterator(); itr.hasNext();){
  138. NovelTypeRelation relation = itr.next();
  139. if (relation.getTypeId().equals(typeId)){
  140. itr.remove();
  141. }
  142. }
  143. }
  144. }

测试类:

  1. public class Client {
  2. public static void main(String[] args) {
  3. NovelTypeMediator mediator = NovelTypeMediator.getInstance();
  4. //展示书单
  5. mediator.showNovelList();
  6. //完结
  7. Novel novel = new Novel("1n", "诛仙");
  8. novel.setFinsh(true);
  9. System.out.println("----------------一本小说完结后的书单------------------");
  10. mediator.showNovelList();
  11. //撤销分类2t
  12. Type type = new Type("2t", "奇异");
  13. type.setUnpopular(true);
  14. System.out.println("----------------删除一个分类后------------------");
  15. mediator.showNovelList();
  16. }
  17. }

这里的Novel和Type都抽象父类,但依旧都可以当作同事类,NovelTypeMediator则为单例中介者。

六、优点和缺点

6.1、优点

中介者模式的主要优点如下:

6.2、缺点

中介者模式的主要缺点如下:

七、适用环境

在以下情况下可以使用中介者模式:

八、模式应用

MVC架构中控制器Controller作为一种中介者,它负责控制视图对象View和模型对象Model之间的交互。如在Struts中,Action就可以作为JSP页面与业务对象之间的中介者。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注