设计模式实战-中介模式,为你牵桥搭线
1、定义
中介者?其实生活中大家再熟悉不过了这个词,我们熟悉的黄牛、房产中介等就是充当中介的角色,将我们的买票、购房等的需求自身消化再代为办理。又比如说中间件,马老师很忙,不能来一个人有事就直接找马老师对吧,所以要找一个中介,客户来了直接找中间人,中间人再和马老师沟通,这样马老师和客户那边就是一个不可见的关系,由中介者角色进行中间协调,马老师也能抽出更多时间去忙别的事了,解放了相当的生产力。
中介者模式(Mediator)的定义:定义一个中介对象来封装对象之间的交互,使原有对象之间耦合松散,并且可以独立地改变它们之间的交互。
还记得迪米特法则吗?迪米特法则的初衷在于降低类之间的耦合,中介者模式就是迪米特法则的典型应用。
2、组成角色
中介者模式的组成角色如下:
- 中介者(又称仲裁者,Mediator):负责定义与 Colleague 角色进行通信和做出角色的接口;
- 具体中介者、仲裁者(ConcreteMediator):负责实现 Mediator 角色定义的接口,负责具体的业务执行;
- 同事角色(Colleague):负责定义与 Mediator 角色进行通信的接口;
- 具体同事角色(ConcreteColleague):实现 Colleague 角色定义的接口,一般会有多个实现类。
类图的话比较简单,就没有细分中介者角色了,抽象成了如下三种角色:
3、代码实现
每个同事角色都知道中介者角色的存在,比如房屋买卖中,卖家和买家都知道房产中介的存在一样,也就是同事角色间进行通信时都必须依赖于中介者角色,当然,如果同事角色只是简单对自身状态进行变更,不会影响其他同事角色的状态时就不需要中介者角色,这种同事角色自发改变自身行为的行为称为自发行为,第二种行为就是依赖其他对象进行操作的行为。
中介者模式的代码如下:
// 抽象同事类
abstract class Colleague {
// 每个同事类角色都必须知道中介者角色的存在
protected Mediator mediator;
public Colleague(Mediator mediator) {
this.mediator = mediator;
}
}
// 具体同事类
class Colleague1 extends Colleague {
public Colleague1(Mediator mediator) {
super(mediator);
}
// 自发行为
public void doSelfMethod1() {
System.out.println("11111");
}
// 依赖方法
public void depMethod1() {
// 委托给中介者处理的任务
this.mediator.doSomething();
}
}
// 具体同事类
class Colleague2 extends Colleague {
public Colleague2(Mediator mediator) {
super(mediator);
}
// 自发行为
public void doSelfMethod2() {
System.out.println("22222");
}
// 依赖方法
public void depMethod2() {
// 委托给中介者处理的任务
this.mediator.doSomething();
}
}
// 抽象中介者角色
abstract class Mediator {
// 中介者要协调的同事角色
protected Colleague1 c1;
protected Colleague2 c2;
// 中介者模式的业务逻辑抽象
abstract void doSomething();
public Colleague1 getC1() {
return c1;
}
public void setC1(Colleague1 c1) {
this.c1 = c1;
}
public Colleague2 getC2() {
return c2;
}
public void setC2(Colleague2 c2) {
this.c2 = c2;
}
}
// 具体中介者
class ConcreteMediator extends Mediator{
@Override
void doSomething() {
this.c1.doSelfMethod1();
this.c2.doSelfMethod2();
}
}
具体的测试类:
// 声明中介者
Mediator mediator = new ConcreteMediator();
// 定义两个同事角色
Colleague1 c1 = new Colleague1(mediator);
Colleague2 c2 = new Colleague2(mediator);
// 给中介者设置同事角色
mediator.setC1(c1);
mediator.setC2(c2);
c1.depMethod1();
3、优缺点
中介者模式的优点:
- 弱化对象间的依赖关系,即松耦合,降低同时类的耦合度,符合迪米特法则
- 将对象间的调用关系进行封装,使得对象更容易复用
中介者模式的缺点:
- 如果对象增多,就要去修改抽象中介者和具体的中介者角色
- 中介者角色承担了太多了业务逻辑功能,流程复杂时就会显得比较臃肿,不好管理
4、应用场景
中介者模式的应用场景一般比较明确,当系统有一系列对象需要相互调用,为弱化对象间的依赖关系,使得这些对象之间松耦合。
生活中,最普遍熟悉的例子就是房屋中介或者 qq 群这种聊天案例,这里我们以房屋中介为例,中介公司就好比我们的中介者角色,而业主和买家就构成了两个不同的同事角色,买卖双方之间的这种交互就可以交给中介者去对接协调:
// 抽象的中介公司角色,中介者角色中一般都要包含各个同事角色,因为它要负责这些对象之间的交互
abstract class MeditorCompany {
// 中介公司名称
private String name;
protected ColleagueSeller seller; // 卖家-同事角色
protected ColleagueBuyer buyer; // 买家-同事角色
// 发布一个需求,由中介公司去代为发布,入参为需求内容、发布人
abstract void publish(String message, Colleaguer colleaguer);
public MeditorCompany(String name) {
this.name = name;
}
public ColleagueSeller getSeller() {
return seller;
}
public void setSeller(ColleagueSeller seller) {
this.seller = seller;
}
public ColleagueBuyer getBuyer() {
return buyer;
}
public void setBuyer(ColleagueBuyer buyer) {
this.buyer = buyer;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
// 具体的中介公司-贝克找房
class MeditorCompanyBeiKe extends MeditorCompany{
public MeditorCompanyBeiKe(String name) {
super(name);
}
@Override
void publish(String message, Colleaguer colleaguer) {
if (colleaguer instanceof ColleagueSeller) { // 如果是卖家发布,则买家进行接收
buyer.accept(message);
} else if(colleaguer instanceof ColleagueBuyer) { // 如果是买家发布,则卖家进行接收
seller.accept(message);
}
}
}
// 抽象的同事角色
abstract class Colleaguer {
protected MeditorCompany meditorCompany; // 对同事类而言,中介者必须是可见的
public Colleaguer(MeditorCompany meditorCompany) {
this.meditorCompany = meditorCompany;
}
}
// 卖家-同事角色
class ColleagueSeller extends Colleaguer {
public ColleagueSeller(MeditorCompany meditorCompany) {
super(meditorCompany);
}
// 同事类发布一个需求,不过是通过中介公司去发布,发布人是自己
public void send(String message) {
meditorCompany.publish(message, this);
}
public void accept(String message) {
System.out.println("卖家接收到的消息是:" + message);
}
}
// 买家-同事角色
class ColleagueBuyer extends Colleaguer {
public ColleagueBuyer(MeditorCompany meditorCompany) {
super(meditorCompany);
}
public void send(String message) {
meditorCompany.publish(message, this);
}
public void accept(String message) {
System.out.println("买家接收到的消息是:" + message);
}
}
测试如下:
// 定义一个中介者
MeditorCompany meditorCompany = new MeditorCompanyBeiKe("贝克找房");
// 定义一个卖家一个买家同事类
ColleagueSeller colleagueSeller = new ColleagueSeller(meditorCompany);
ColleagueBuyer colleagueBuyer = new ColleagueBuyer(meditorCompany);
// 给中介公司注册买家、卖家
meditorCompany.setBuyer(colleagueBuyer);
meditorCompany.setSeller(colleagueSeller);
// 操作
colleagueSeller.send("卖家发布需求...");
colleagueBuyer.send("买家发布需求...");
结果输出:
买家接收到的消息是:卖家发布需求...
卖家接收到的消息是:买家发布需求...
中介者模式的引入,其实就是为了解决系统对象相互依赖调用的情况,可以想象一下,使用中介者模式后,原本的错综复杂的网络结构就会变成以中介者为中心的网状结构,这是中介者模式要解决的问题。
5、总结
本节我们介绍了中介者模式,要注意的就是,中介者角色承担了太多的业务功能,并且中介者角色依赖具体的同事角色,一旦同事角色有变更或者添加,中介者角色就需要相应地发生变化,导致二次开发维护变得困难,所以使用的过程中还是要多加注意。
- 深入挖掘APP克隆实验
- Sickle:推荐一款优质ShellCode开发工具
- 看我教你如何修改QQ安装包实现绕过QQ语音红包验证来领红包
- “奇幻熊”(APT28)组织最新攻击
- GDB调试CVE-2018-5711 PHP-GD拒绝服务漏洞
- 高效与争议并存:大规模自动化渗透工具AutoSploit
- Android应用测试速查表
- ADB配置提权漏洞(CVE-2017-13212)原理与利用分析
- Fuzz自动化Bypass软WAF姿势
- Web黑盒渗透思路之猜想
- ZZCMS v8.2 最新版SQL注入漏洞
- 一款轻量级Web漏洞教学演示系统(DSVW)
- 使用Burpsuite代理和pypcap抓包进行抢红包的尝试
- 基于WAVSEP的靶场搭建指南
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Python 技术篇-如何打印一段文字,用友云霸气控制台颜文字打印
- Python 技术篇-获取秒级时间戳、毫秒级时间戳
- Python 技术篇-基于随机数的uuid码的生成
- BAT 脚本技术-利用bat批处理脚本静态指定ip地址、自动获取ip地址设置
- Oracle 技巧篇-快速批量删除当前数据库连接的用户,一键清空所有session会话方法
- Spring Security 中如何细化权限粒度?
- 小书MybatisPlus第4篇-表格分页与下拉分页查询
- 小书MybatisPlus第3篇-自定义SQL
- Nginx + Spring Boot 实现负载均衡
- 小书MybatisPlus第2篇-条件构造器的应用及总结
- 一个案例演示 Spring Security 中粒度超细的权限控制!
- 信息收集之主机发现:nmap
- 文本文件逐行处理–用java8 Stream流的方式
- 使用java8API遍历过滤文件目录及子目录及隐藏文件
- 使用位运算、值交换等方式反转java字符串-共四种方法