文章目录
- 1 中介者模式(Mediator Pattern)
- 1.1 介绍
- 1.2 概述
- 1.3 中介者模式的结构
- 1.4 中介者模式的优缺点
- 1.5 中介者模式的使用场景
- 2 案例一
- 2.1 需求
- 2.2 代码实现
- 3 案例二
- 3.1 需求
- 3.2 代码实现
🙊 前言:本文章为瑞_系列专栏之《23种设计模式》的中介者模式篇。本文中的部分图和概念等资料,来源于博主学习设计模式的相关网站《菜鸟教程 | 设计模式》和《黑马程序员Java设计模式详解》,特此注明。本文中涉及到的软件设计模式的概念、背景、优点、分类、以及UML图的基本知识和设计模式的6大法则等知识,建议阅读 《瑞_23种设计模式_概述》
本系列 - 设计模式 - 链接:《瑞_23种设计模式_概述》
⬇️本系列 - 创建型模式 - 链接🔗单例模式:《瑞_23种设计模式_单例模式》
工厂模式:《瑞_23种设计模式_工厂模式》
原型模式:《瑞_23种设计模式_原型模式》
抽象工厂模式:《瑞_23种设计模式_抽象工厂模式》
建造者模式:《瑞_23种设计模式_建造者模式》⬇️本系列 - 结构型模式 - 链接🔗
代理模式:《瑞_23种设计模式_代理模式》
适配器模式:《瑞_23种设计模式_适配器模式》
装饰者模式:《瑞_23种设计模式_装饰者模式》
桥接模式:《瑞_23种设计模式_桥接模式》
外观模式:《瑞_23种设计模式_外观模式》
组合模式:《瑞_23种设计模式_组合模式》
享元模式:《瑞_23种设计模式_享元模式》⬇️本系列 - 行为型模式 - 链接🔗
模板方法模式:《瑞_23种设计模式_模板方法模式》
策略模式:《瑞_23种设计模式_策略模式》
命令模式:《瑞_23种设计模式_命令模式》
职责链模式:《瑞_23种设计模式_职责链模式》
状态模式:《瑞_23种设计模式_状态模式》
观察者模式:《瑞_23种设计模式_观察者模式》
中介者模式:《后续更新》
迭代器模式:《后续更新》
访问者模式:《后续更新》
备忘录模式:《后续更新》
解释器模式:《后续更新》
1 中介者模式(Mediator Pattern)
瑞:中介者模式在框架设计中经常使用,即使框架内部再复杂,其使用方法也会相对简单。如Spring框架中的 BeanFactory 就是中介者模式的一个实现,它作为中介者,负责管理和创建应用程序中的所有 beans ,而不是让 beans 直接相互引用或创建。
中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。中介者模式属于行为型模式。
瑞:行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。
瑞:行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。
中介者模式属于:对象行为模式
1.1 介绍
-
意图:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
-
主要解决:对象与对象之间存在大量的关联关系,这样势必会导致系统的结构变得很复杂,同时若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应的处理。
-
何时使用:多个类相互耦合,形成了网状结构。
-
如何解决:将上述网状结构分离为星型结构。
-
关键代码:对象 Colleague 之间的通信封装到一个类中单独处理。
-
应用实例:
1️⃣ 中国加入 WTO 之前是各个国家相互贸易,结构复杂,现在是各个国家通过 WTO 来互相贸易。
2️⃣ 机场调度系统。
3️⃣ MVC 框架,其中C(控制器)就是 M(模型)和 V(视图)的中介者。 -
优点:
1️⃣ 降低了类的复杂度,将一对多转化成了一对一。
2️⃣ 各个类之间的解耦。
3️⃣ 符合迪米特原则。 -
缺点:
1️⃣ 中介者会庞大,变得复杂难以维护。 -
使用场景:
1️⃣ 系统中对象之间存在比较复杂的引用关系,导致它们之间的依赖关系结构混乱而且难以复用该对象。
2️⃣ 想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。 -
注意事项:
1️⃣ 不应当在职责混乱的时候使用
1.2 概述
定义:中介者模式又叫调停模式,定义一个中介角色来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。
一般来说,同事类之间的关系是比较复杂的,多个同事类之间互相关联时,他们之间的关系会呈现为复杂的网状结构,这是一种过度耦合的架构,即不利于类的复用,也不稳定。例如在下左图中,有六个同事类对象,假如对象1发生变化,那么将会有4个对象受到影响。如果对象2发生变化,那么将会有5个对象受到影响。也就是说,同事类之间直接关联的设计是不好的。
如果引入中介者模式,那么同事类之间的关系将变为星型结构,从下图中可以看到,任何一个类的变动,只会影响的类本身,以及中介者,这样就减小了系统的耦合。一个好的设计,必定不会把所有的对象关系处理逻辑封装在本类中,而是使用一个专门的类来管理那些不属于自己的行为。
1.3 中介者模式的结构
- 中介者模式主要包含以下角色:
1️⃣ Subject:抽象中介者(Mediator)角色:它是中介者的接口,提供了同事对象注册与转发同事对象信息的抽象方法。
2️⃣ 具体中介者(ConcreteMediator)角色:实现中介者接口,定义一个 List 来管理同事对象,协调各个同事角色之间的交互关系,因此它依赖于同事角色。
3️⃣ 抽象同事类(Colleague)角色:定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。
4️⃣ 具体同事类(Concrete Colleague)角色:是抽象同事类的实现者,当需要与其他同事对象交互时,由中介者对象负责后续的交互。
1.4 中介者模式的优缺点
优点:
-
松散耦合
中介者模式通过把多个同事对象之间的交互封装到中介者对象里面,从而使得同事对象之间松散耦合,基本上可以做到互补依赖。这样一来,同事对象就可以独立地变化和复用,而不再像以前那样“牵一处而动全身”了。 -
集中控制交互
多个同事对象的交互,被封装在中介者对象里面集中管理,使得这些交互行为发生变化的时候,只需要修改中介者对象就可以了,当然如果是已经做好的系统,那么就扩展中介者对象,而各个同事类不需要做修改。 -
一对多关联转变为一对一的关联
没有使用中介者模式的时候,同事对象之间的关系通常是一对多的,引入中介者对象以后,中介者对象和同事对象的关系通常变成双向的一对一,这会让对象的关系更容易理解和实现。
缺点:
- 当同事类太多时,中介者的职责将很大,它会变得复杂而庞大,以至于系统难以维护。
1.5 中介者模式的使用场景
- 系统中对象之间存在复杂的引用关系,系统结构混乱且难以理解。
- 当想创建一个运行于多个类之间的对象,又不想生成新的子类时。
2 案例一
【案例】租房
2.1 需求
现在租房基本都是通过房屋中介,房主将房屋托管给房屋中介,而租房者从房屋中介获取房屋信息。房屋中介充当租房者与房屋所有者之间的中介者。
类图如下:
2.2 代码实现
/**
* 抽象中介者类
*
* @author LiaoYuXing-Ray
**/
public abstract class Mediator {
// 沟通
public abstract void contact(String message, Person person);
}
/**
* 抽象同事类
*
* @author LiaoYuXing-Ray
**/
public abstract class Person {
// 租房者或者房主的姓名
protected String name;
// 中介
protected Mediator mediator;
public Person(String name, Mediator mediator) {
this.name = name;
this.mediator = mediator;
}
}
/**
* 具体的同事角色类
*
* @author LiaoYuXing-Ray
**/
public class HouseOwner extends Person {
public HouseOwner(String name, Mediator mediator) {
super(name, mediator);
}
// 和中介联系(沟通)
public void contact(String message) {
mediator.contact(message,this);
}
// 获取信息
public void getMessage(String message) {
System.out.println("房主" + name + "获取到的信息是:" + message);
}
}
/**
* 具体的同事角色类
*
* @author LiaoYuXing-Ray
**/
public class Tenant extends Person {
public Tenant(String name, Mediator mediator) {
super(name, mediator);
}
// 和中介联系(沟通)
public void contact(String message) {
mediator.contact(message,this);
}
// 获取信息
public void getMessage(String message) {
System.out.println("租房者" + name + "获取到的信息是:" + message);
}
}
/**
* 具体的中介者角色类
*
* @author LiaoYuXing-Ray
**/
public class MediatorStructure extends Mediator {
// 聚合房主和租房者对象
private HouseOwner houseOwner;
private Tenant tenant;
public HouseOwner getHouseOwner() {
return houseOwner;
}
public void setHouseOwner(HouseOwner houseOwner) {
this.houseOwner = houseOwner;
}
public Tenant getTenant() {
return tenant;
}
public void setTenant(Tenant tenant) {
this.tenant = tenant;
}
public void contact(String message, Person person) {
if(person == houseOwner) {
tenant.getMessage(message);
} else {
houseOwner.getMessage(message);
}
}
}
/**
* 测试类
*
* @author LiaoYuXing-Ray
**/
public class Client {
public static void main(String[] args) {
// 创建中介者对象
MediatorStructure mediator = new MediatorStructure();
// 创建租房者对象
Tenant tenant = new Tenant("李四",mediator);
// 创建房主对象
HouseOwner houseOwner = new HouseOwner("张三",mediator);
// 中介者要知道具体的房主和租房者
mediator.setTenant(tenant);
mediator.setHouseOwner(houseOwner);
tenant.contact("要租三室的房子!!!");
houseOwner.contact("我这里有三室的房子,你要租吗?");
}
}
代码运行结果如下:
房主张三获取到的信息是:要租三室的房子!!!
租房者李四获取到的信息是:我这里有三室的房子,你要租吗?
3 案例二
本案例为菜鸟教程中的案例
3.1 需求
我们通过聊天室实例来演示中介者模式。实例中,多个用户可以向聊天室发送消息,聊天室向所有的用户显示消息。我们将创建两个类 ChatRoom 和 User。User 对象使用 ChatRoom 方法来分享他们的消息。
MediatorPatternDemo,我们的演示类使用 User 对象来显示他们之间的通信。
3.2 代码实现
步骤 1
创建中介类。
import java.util.Date;
public class ChatRoom {
public static void showMessage(User user, String message){
System.out.println(new Date().toString()
+ " [" + user.getName() +"] : " + message);
}
}
步骤 2
创建 user 类。
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User(String name){
this.name = name;
}
public void sendMessage(String message){
ChatRoom.showMessage(this,message);
}
}
步骤 3
使用 User 对象来显示他们之间的通信。
public class MediatorPatternDemo {
public static void main(String[] args) {
User robert = new User("Robert");
User john = new User("John");
robert.sendMessage("Hi! John!");
john.sendMessage("Hello! Robert!");
}
}
步骤 4
执行程序,输出结果:
Thu Jan 31 16:05:46 IST 2013 [Robert] : Hi! John!
Thu Jan 31 16:05:46 IST 2013 [John] : Hello! Robert!
如果觉得这篇文章对您有所帮助的话,请动动小手点波关注💗,你的点赞👍收藏⭐️转发🔗评论📝都是对博主最好的支持~