详解Java设计模式编程中的中介者模式

 更新时间:2016年02月05日 09:36:27   作者:卡奴达摩  
这篇文章主要介绍了Java设计模式编程中的中介者模式,文中举了典型的同事类与中介者类的例子来解释说明,需要的朋友可以参考下

定义:用一个中介者对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使耦合松散,而且可以独立地改变它们之间的交互。
类型:行为类模式
类图:

20162593206564.jpg (526×202)

中介者模式的结构
       中介者模式又称为调停者模式,从类图中看,共分为3部分:
 抽象中介者:定义好同事类对象到中介者对象的接口,用于各个同事类之间的通信。一般包括一个或几个抽象的事件方法,并由子类去实现。
中介者实现类:从抽象中介者继承而来,实现抽象中介者中定义的事件方法。从一个同事类接收消息,然后通过消息影响其他同时类。
同事类:如果一个对象会影响其他的对象,同时也会被其他对象影响,那么这两个对象称为同事类。在类图中,同事类只有一个,这其实是现实的省略,在实际应用中,同事类一般由多个组成,他们之间相互影响,相互依赖。同事类越多,关系越复杂。并且,同事类也可以表现为继承了同一个抽象类的一组实现组成。在中介者模式中,同事类之间必须通过中介者才能进行消息传递。
为什么要使用中介者模式
       一般来说,同事类之间的关系是比较复杂的,多个同事类之间互相关联时,他们之间的关系会呈现为复杂的网状结构,这是一种过度耦合的架构,即不利于类的复用,也不稳定。例如在下图中,有六个同事类对象,假如对象1发生变化,那么将会有4个对象受到影响。如果对象2发生变化,那么将会有5个对象受到影响。也就是说,同事类之间直接关联的设计是不好的。

20162593302973.jpg (431×252)20162593327585.jpg (419×251)

如果引入中介者模式,那么同事类之间的关系将变为星型结构,从图中可以看到,任何一个类的变动,只会影响的类本身,以及中介者,这样就减小了系统的耦合。一个好的设计,必定不会把所有的对象关系处理逻辑封装在本类中,而是使用一个专门的类来管理那些不属于自己的行为。

20162593346671.jpg (427×357)


下面给出具体的代码例子,对比通用类图增加了AbstractColleague抽象同事类和AbstractMediator抽象中介者,另外就是两个具体同事类和一个具体中介者,代码中有较多注释,相应类图也不给出了,应该不难理解的:
 
同事类族:

//抽象同事类 
abstract class AbstractColleague { 
  protected AbstractMediator mediator; 
   
  /**既然有中介者,那么每个具体同事必然要与中介者有联系, 
   * 否则就没必要存在于 这个系统当中,这里的构造函数相当 
   * 于向该系统中注册一个中介者,以取得联系 
   */ 
  public AbstractColleague(AbstractMediator mediator) { 
    this.mediator = mediator; 
  } 
   
  // 在抽象同事类中添加用于与中介者取得联系(即注册)的方法 
  public void setMediator(AbstractMediator mediator) { 
    this.mediator = mediator; 
  } 
} 
 
//具体同事A 
class ColleagueA extends AbstractColleague { 
   
  //每个具体同事都通过父类构造函数与中介者取得联系 
  public ColleagueA(AbstractMediator mediator) { 
    super(mediator); 
  } 
   
  //每个具体同事必然有自己分内的事,没必要与外界相关联 
  public void self() { 
    System.out.println("同事A --> 做好自己分内的事情 ..."); 
  } 
   
  //每个具体同事总有需要与外界交互的操作,通过中介者来处理这些逻辑并安排工作 
  public void out() { 
    System.out.println("同事A --> 请求同事B做好分内工作 ..."); 
    super.mediator.execute("ColleagueB", "self"); 
  } 
} 
 
//具体同事B 
class ColleagueB extends AbstractColleague { 
   
  public ColleagueB(AbstractMediator mediator) { 
    super(mediator); 
  } 
   
  public void self() { 
    System.out.println("同事B --> 做好自己分内的事情 ..."); 
  } 
   
  public void out() { 
    System.out.println("同事B --> 请求同事A做好分内工作 ..."); 
    super.mediator.execute("ColleagueA", "self"); 
  } 
} 

中介者类族:

//抽象中介者 
abstract class AbstractMediator { 
   
  //中介者肯定需要保持有若干同事的联系方式 
  protected Hashtable<String, AbstractColleague> colleagues = new Hashtable<String, AbstractColleague>(); 
   
  //中介者可以动态地与某个同事建立联系 
  public void addColleague(String name, AbstractColleague c) { 
    this.colleagues.put(name, c); 
  }   
   
  //中介者也可以动态地撤销与某个同事的联系 
  public void deleteColleague(String name) { 
    this.colleagues.remove(name); 
  } 
   
  //中介者必须具备在同事之间处理逻辑、分配任务、促进交流的操作 
  public abstract void execute(String name, String method);  
} 
 
//具体中介者 
class Mediator extends AbstractMediator{ 
   
  //中介者最重要的功能,来回奔波与各个同事之间 
  public void execute(String name, String method) { 
     
    if("self".equals(method)){ //各自做好分内事 
      if("ColleagueA".equals(name)) { 
        ColleagueA colleague = (ColleagueA)super.colleagues.get("ColleagueA"); 
        colleague.self(); 
      }else { 
        ColleagueB colleague = (ColleagueB)super.colleagues.get("ColleagueB"); 
        colleague.self(); 
      } 
    }else { //与其他同事合作 
      if("ColleagueA".equals(name)) { 
        ColleagueA colleague = (ColleagueA)super.colleagues.get("ColleagueA"); 
        colleague.out(); 
      }else { 
        ColleagueB colleague = (ColleagueB)super.colleagues.get("ColleagueB"); 
        colleague.out(); 
      } 
    } 
  } 
} 

测试类:

//测试类 
public class Client { 
  public static void main(String[] args) { 
     
    //创建一个中介者 
    AbstractMediator mediator = new Mediator(); 
     
    //创建两个同事 
    ColleagueA colleagueA = new ColleagueA(mediator); 
    ColleagueB colleagueB = new ColleagueB(mediator); 
     
    //中介者分别与每个同事建立联系 
    mediator.addColleague("ColleagueA", colleagueA); 
    mediator.addColleague("ColleagueB", colleagueB); 
     
    //同事们开始工作 
    colleagueA.self(); 
    colleagueA.out(); 
    System.out.println("======================合作愉快,任务完成!\n"); 
     
    colleagueB.self(); 
    colleagueB.out(); 
    System.out.println("======================合作愉快,任务完成!"); 
  } 
} 

测试结果: 

同事A --> 做好自己分内的事情 ... 
同事A --> 请求同事B做好分内工作 ... 
同事B --> 做好自己分内的事情 ... 
======================合作愉快,任务完成! 
 
同事B --> 做好自己分内的事情 ... 
同事B --> 请求同事A做好分内工作 ... 
同事A --> 做好自己分内的事情 ... 
======================合作愉快,任务完成! 

 
虽然以上代码中只有两个具体同事类,并且测试类中也只是创建了两个同事,但是这些我们都可以根据中介者模式的宗旨进行适当地扩展,即增加具体同事类,然后中介者就得担负更加重的任务了。为啥?我们看到上面具体中介者类Mediator中的execute()方法中现在就有一堆冗长的判断代码了。虽然可以把它分解并增加到Mediator类中的其它private方法中,但是具体的业务逻辑是少不了的。
 
所以,在解耦同事类之间的联系的同时,中介者自身也不免任务过重,因为几乎所有的业务逻辑都交代到中介者身上了,可谓是“万众期待”的一个角色了。这就是中介者模式的不足之处了 。
此外,上面这个代码例子是相当理想的了,有时候我们根本抽取不了“同事”之间的共性来形成一个AbstractColleague抽象同事类,这也大大增加了中介者模式的使用难度。  
修改:
由于上面代码实现中存在 benjielin 前辈提出的“双向关联暴露在App中”的不足之处,根据给出的改进方法2,修改上面代码,如下:
 
修改后的同事类族:
 

//抽象同事类 
abstract class AbstractColleague { 
  protected AbstractMediator mediator;   
   
  //舍去在构造函数中建立起与中介者的联系 
// public AbstractColleague(AbstractMediator mediator) { 
//   this.mediator = mediator; 
// } 
   
  // 在抽象同事类中添加用于与中介者取得联系(即注册)的方法 
  public void setMediator(AbstractMediator mediator) { 
    this.mediator = mediator; 
  } 
} 
 
//具体同事A 
class ColleagueA extends AbstractColleague { 
   
  //舍去在构造函数中建立起与中介者的联系 
// public ColleagueA(AbstractMediator mediator) { 
//   super(mediator); 
// } 
   
  //每个具体同事必然有自己分内的事,没必要与外界相关联 
  public void self() { 
    System.out.println("同事A --> 做好自己分内的事情 ..."); 
  } 
   
  //每个具体同事总有需要与外界交互的操作,通过中介者来处理这些逻辑并安排工作 
  public void out() { 
    System.out.println("同事A --> 请求同事B做好分内工作 ..."); 
    super.mediator.execute("ColleagueB", "self"); 
  } 
} 
 
//具体同事B 
class ColleagueB extends AbstractColleague { 
  //舍去在构造函数中建立起与中介者的联系 
// public ColleagueB(AbstractMediator mediator) { 
//   super(mediator); 
// } 
   
  public void self() { 
    System.out.println("同事B --> 做好自己分内的事情 ..."); 
  } 
   
  public void out() { 
    System.out.println("同事B --> 请求同事A做好分内工作 ..."); 
    super.mediator.execute("ColleagueA", "self"); 
  } 
} 

 
修改后的中介者:

 //抽象中介者 
abstract class AbstractMediator { 
   
  //中介者肯定需要保持有若干同事的联系方式 
  protected Hashtable<String, AbstractColleague> colleagues = new Hashtable<String, AbstractColleague>(); 
   
  //中介者可以动态地与某个同事建立联系 
  public void addColleague(String name, AbstractColleague c) { 
     
    // 在中介者这里帮助具体同事建立起于中介者的联系 
    c.setMediator(this); 
    this.colleagues.put(name, c); 
  }   
   
  //中介者也可以动态地撤销与某个同事的联系 
  public void deleteColleague(String name) { 
    this.colleagues.remove(name); 
  } 
   
  //中介者必须具备在同事之间处理逻辑、分配任务、促进交流的操作 
  public abstract void execute(String name, String method);  
} 
//测试类 
public class Client { 
  public static void main(String[] args) { 
     
    //创建一个中介者 
    AbstractMediator mediator = new Mediator(); 
     
    //不用构造函数为具体同事注册中介者来取得联系了 
//   ColleagueA colleagueA = new ColleagueA(mediator); 
//   ColleagueB colleagueB = new ColleagueB(mediator); 
     
    ColleagueA colleagueA = new ColleagueA(); 
    ColleagueB colleagueB = new ColleagueB(); 
     
    //中介者分别与每个同事建立联系 
    mediator.addColleague("ColleagueA", colleagueA); 
    mediator.addColleague("ColleagueB", colleagueB); 
     
    //同事们开始工作 
    colleagueA.self(); 
    colleagueA.out(); 
    System.out.println("======================合作愉快,任务完成!\n"); 
     
    colleagueB.self(); 
    colleagueB.out(); 
    System.out.println("======================合作愉快,任务完成!"); 
  } 
} 

  测试之后的结果与修改前一样。

相关文章

  • JavaWeb 中Cookie实现记住密码的功能示例

    JavaWeb 中Cookie实现记住密码的功能示例

    cookie是一种WEB服务器通过浏览器在访问者的硬盘上存储信息的手段。Cookie的目的就是为用户带来方便,为网站带来增值。这篇文章主要介绍了JavaWeb 中Cookie实现记住密码的功能示例,需要的朋友可以参考下
    2017-06-06
  • Java实现驼峰和下划线互相转换的示例代码

    Java实现驼峰和下划线互相转换的示例代码

    Java对各种变量、方法和类等要素命名时使用的字符序列称为标识符,凡是自己可以起名字的地方都叫标识符。本文为大家分享了Java中如何实现驼峰命名与下划线命名的互转,感兴趣的可以了解一下
    2022-05-05
  • Java中的@Builder注解问题详解

    Java中的@Builder注解问题详解

    这篇文章主要介绍了Java中的@Builder注解详解,@Builder 注解的其中一个大坑会导致默认值失效,这是使用此注解出现的一个问题,总的来说,不推荐再使用 @Builder 注解,接下来讲重点介绍其原因和替代方案,需要的朋友可以参考下
    2023-10-10
  • Java concurrency线程池之线程池原理(二)_动力节点Java学院整理

    Java concurrency线程池之线程池原理(二)_动力节点Java学院整理

    这篇文章主要为大家详细介绍了Java concurrency线程池之线程池原理第二篇,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06
  • spring @Lazy延迟注入的逻辑实现

    spring @Lazy延迟注入的逻辑实现

    有时候我们会在属性注入的时候添加@Lazy注解实现延迟注入,今天咱们通过阅读源码来分析下原因,感兴趣的可以了解一下
    2021-08-08
  • SpringBoot实现登录拦截的示例代码

    SpringBoot实现登录拦截的示例代码

    如果我们不进行登录拦截的话,即使我们跳过登录页面直接去访问任意一个页面也能访问成功,那么登录功能就没有意义,同时也会存在安全问题,本文就来介绍一下SpringBoot登录拦截,具有一定的参考价值,感兴趣的可以了解一下
    2023-09-09
  • Spring Boot无缝集成MongoDB

    Spring Boot无缝集成MongoDB

    这篇文章主要介绍了Spring Boot无缝集成MongoDB的相关知识,本文涉及到MongoDB的概念和nosql的应用场景,需要的朋友可以参考下
    2017-04-04
  • 一文掌握Spring的创建与使用

    一文掌握Spring的创建与使用

    这篇文章详细介绍了spring的创建与使用,文章中有详细的代码示例和图片介绍,对学习有一定的而参考价值,需要的同学可以参考一下
    2023-04-04
  • Spring运行时手动注入bean的方法实例

    Spring运行时手动注入bean的方法实例

    spring给我们提供了IOC服务,让我们可以用注解的方式,方便的使用bean的相互引用,下面这篇文章主要给大家介绍了关于Spring运行时手动注入bean的相关资料,需要的朋友可以参考下
    2022-05-05
  • java实现微信H5支付方法详解

    java实现微信H5支付方法详解

    本篇文章主要介绍了java实现微信H5支付方法详解,非常具有实用价值,需要的朋友可以参考下
    2017-04-04

最新评论