本文节选自《设计模式就该这样学》

1 中介者模式的应用场景

在现实生活中,中介者的存在是不可缺少的,如果没有了中介者,我们就不能与远方的朋友进行交流。各个同事对象将会相互进行引用,如果每个对象都与多个对象进行交互,则会形成如下图所示的网状结构。

从上图可以看到,每个对象之间都过度耦合,这样既不利于信息的复用也不利于扩展。如果引入中介者模式,则对象之间的关系将变成星形结构,如下图所示。

从上图可以看到,使用中介者模式后,任何一个类的变化,只会影响中介者和类本身,不像之前的设计,任何一个类的变化都会引起其关联的所有类的变化。这样的设计大大减少了系统的耦合度。

其实日常生活中我们每天都在刷的朋友圈,就是一个中介者。还有我们所见的信息交易平台,也是中介者模式的体现。

中介者模式是用来降低多个对象和类之间的通信复杂性的。这种模式通过提供一个中介类,将系统各层次对象间的多对多关系变成一对多关系,中介者对象可以将复杂的网状结构变成以中介者为中心的星形结构,达到降低系统的复杂性、提高可扩展性的作用。

若系统各层次对象之间存在大量的关联关系,即层次对象呈复杂的网状结构,如果直接让它们紧耦合通信,会使系统结构变得异常复杂,且当其中某个层次对象发生改变时,则与其紧耦合的相应层次对象也需进行修改,系统很难进行维护。

简单地说,如果多个类相互耦合,形成了网状结构,则考虑使用中介者模式进行优化。总结一下,中介者模式主要适用于以下应用场景。

(1)系统中对象之间存在复杂的引用关系,产生的相互依赖关系结构混乱且难以理解。

(2)交互的公共行为,如果需要改变行为,则可以增加新的中介者类。

2 中介者模式的UML类图

中介者模式的UML类图如下图所示。

3 使用中介者模式设计群聊场景

假设我们要构建一个聊天室系统,用户可以向聊天室发送消息,聊天室会向所有用户显示消息。实际上就是用户发信息与聊天室显示的通信过程,不过用户无法直接将信息发给聊天室,而需要将信息先发到服务器上,然后服务器再将该消息发给聊天室进行显示,具体代码如下。首先创建User类。


public class User {
private String name;
private ChatRoom chatRoom; public User(String name, ChatRoom chatRoom) {
this.name = name;
this.chatRoom = chatRoom;
} public void sendMessage(String msg) {
this.chatRoom.showMsg(this, msg);
} public String getName() {
return name;
}
}

然后创建ChatRoom类。


public class ChatRoom {
public void showMsg(User user, String msg) {
System.out.println("[" + user.getName() + "] :" + msg);
}
}

最后编写客户端测试代码。


public static void main(String[] args) {
ChatRoom room = new ChatRoom(); User tom = new User("Tom",room);
User jerry = new User("Jerry",room);
tom.sendMessage("Hi! I am Tom.");
jerry.sendMessage("Hello! My name is Jerry.");
}

运行结果如下图所示。

4 中介者模式在JDK源码中的应用

首先来看JDK中的Timer类。打开Timer的结构,我们发现Timer类中有很多schedule()重载方法,如下图所示。

任意点开其中一个方法,我们发现所有方法最终都调用了私有的schedule()方法,源码如下。


public class Timer {
...
public void schedule(TimerTask task, long delay) {
if (delay < 0)
throw new IllegalArgumentException("Negative delay.");
sched(task, System.currentTimeMillis()+delay, 0);
}
...
private void sched(TimerTask task, long time, long period) {
if (time < 0)
throw new IllegalArgumentException("Illegal execution time."); if (Math.abs(period) > (Long.MAX_VALUE >> 1))
period >>= 1; synchronized(queue) {
if (!thread.newTasksMayBeScheduled)
throw new IllegalStateException("Timer already cancelled."); synchronized(task.lock) {
if (task.state != TimerTask.VIRGIN)
throw new IllegalStateException(
"Task already scheduled or cancelled");
task.nextExecutionTime = time;
task.period = period;
task.state = TimerTask.SCHEDULED;
} queue.add(task);
if (queue.getMin() == task)
queue.notify();
}
}
...
}

而且,不管是什么样的任务都被加入一个队列中按顺序执行。我们把这个队列中的所有对象都称为“同事”。同事之间的通信都是通过Timer来协调完成的,Timer承担了中介者的角色。

关注微信公众号『 Tom弹架构 』回复“设计模式”可获取完整源码。

【推荐】Tom弹架构:30个设计模式真实案例(附源码),挑战年薪60W不是梦

本文为“Tom弹架构”原创,转载请注明出处。技术在于分享,我分享我快乐!

如果本文对您有帮助,欢迎关注和点赞;如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力。关注微信公众号『 Tom弹架构 』可获取更多技术干货!

微信和QQ这么多群,该如何管理好友关系?的更多相关文章

  1. 微信、QQ群短文本聊天语料总结

    在文本分类任务中,语料的特性千差万别,我们需要找到适合模型并抓住数据的特性,最终才能得到较好的model.最近在文本类别标注任务,就是给文本打标签确定该文本的类别.这是一个很费人工的过程,需要认真仔细 ...

  2. 为什么我们不应该使用微信或者 QQ 作为团队协作的 IM 工具?

    如果你的团队没有觉得微信是低效的团队 IM 工具,那只有两种可能: 团队成员很少使用微信进行私人的生活和娱乐. 你就是一个低效的团队,而且还不自知. 本文内容 微信,连接一切 每个人都有微信 微信,低 ...

  3. 支付宝、微信、QQ 收款二维码三合一

    最近折腾了一下合并收款码,简单记录一下折腾的过程,方法不唯一,只是提供一种思路,如果各位大佬有更加简单粗暴的办法,那就更好了. 原理 首先解析出三个二维码的内容,用 Nginx 判断 User age ...

  4. Android 高仿微信(QQ)滑动弹出编辑、删除菜单效果,增加下拉刷新功能

    不可否认,微信.QQ列表的滑动删除.编辑功能着实很经典(从IOS那边模仿过来的),然.Android这边,对列表的操作,其实大多还停留上下文菜单来实现. Android如何实现list item的滑动 ...

  5. React Native 接入微博、微信、QQ 登录功能

    在 App 开发中我们经常需要在用户登录模块接入 SNS 登录组件,这样会大大提高用户的注册体验.特别当一个不是刚性需求 App 推广的时候,这样会很大的降低用户体验的成本,没有人愿意忍受输入邮箱.手 ...

  6. app分享时判断手机是否已安装微信或QQ客户端

    /** * 判断 用户是否安装微信客户端 */ public static boolean isWeixinAvilible(Context context) { final PackageManag ...

  7. ShareSDK集成微信、QQ、微博分享

    1.前言 为什么要使用第三方的作为集成分享的工具呢?而不去用官方的呢?有什么区别么? 一个字"快",如果你使用官方的得一个个集成他们的SDK,相信这是一个痛苦的过程. 2.准备需要 ...

  8. 微信、QQ这类IM App怎么做——谈谈Websocket

    前言 关于我和WebSocket的缘:我从大二在计算机网络课上听老师讲过之后,第一次使用就到了毕业之后的第一份工作.直到最近换了工作,到了一家是含有IM社交聊天功能的app的时候,我觉得我现在可以谈谈 ...

  9. 微信、QQ和手机号之间不得不说的故事!

    发文字,发图片,发心情,视频聊天,查看附近的人,微信能干的事情QQ都可以,那么它们有什么区别,我QQ用得好好的为什么要我联系人都导到微信去?我们很早就有了QQ,但是在QQ时代,我们虽然用QQ发消息聊天 ...

随机推荐

  1. CTF入门记录(1

    (https://ctf-wiki.org) 00 基础了解 CTF简介 (wolai.com) 00-1 CTF题目类型 Web 大部分情况下和网.Web.HTTP等相关技能有关. Web攻防的一些 ...

  2. Tomcat实现自定义类加载器

    什么是类加载器? 这是官方给的定义 在 Java 虚拟机的实现中,初始类可以作为命令行参数提供. 或者,该实现可以提供一个初始类,该类设置一个类加载器,该类加载器依次加载应用程序. 初始类的其他选择也 ...

  3. NX二次开发 克隆

    NXOpen.UF.UFSession theUfSession = NXOpen.UF.UFSession.GetUFSession(); try { //初始化 NXOpen.UF.UFClone ...

  4. from athletelist import AthleteList出现红色下滑波浪线警告

    问题:from athletelist import AthleteList出现红色下滑波浪线警告 经过个人网上搜索了解,这个问题是因为python找不到相关的.py文件,无法导入athletelis ...

  5. JavaScript05

    显示和隐藏 元素的显示和隐藏 元素display属性可控制元素的显示和隐藏,先获取元素对象,再通过点语法调用style对象中的display属性 语法格式: 元素.style.display='non ...

  6. 【UE4 C++】定时器 Timer 与事件绑定

    概念 定时执行操作,可执行一次,或循环执行直到手动终止 定时器在全局定时器管理器(FTimerManager 类型)中管理.全局定时器管理器存在于 游戏实例 对象上以及每个 场景 中 定时器需要绑定委 ...

  7. PyCharm中目录directory与包package的区别及相关import详解

    一.概念介绍 在介绍目录directory与包package的区别之前,先理解一个概念---模块 模块的定义:本质就是以.py结尾的python文件,模块的目的是为了其他程序进行引用. 目录(Dire ...

  8. [敏捷软工团队博客]Beta阶段发布声明

    项目 内容 2020春季计算机学院软件工程(罗杰 任健) 博客园班级博客 作业要求 Beta阶段发布声明 我们在这个课程的目标是 在团队合作中锻炼自己 这个作业在哪个具体方面帮助我们实现目标 对Bet ...

  9. CF375D Tree and Queries 题解

    感觉CF的题目名都好朴素的样子 你谷链接 首先这题显然是个dsu on tree 但是我不会. 其次这题显然是个莫队.这我会啊! 然后会发现好像不是很对劲.因为每次询问都有一个k,貌似和传统的莫队数颜 ...

  10. RMQ、ST表

    ST表 \(\text{ST}\) 表是用于解决可重复贡献问题的数据结构. 可重复贡献问题:区间按位和.区间按位或.区间 \(\gcd\) .区间最大.区间最小等满足结合律且可重复统计的问题. 模板预 ...