名称
中介者模式(MEDIATOR)
目的
用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
适用性
在下列情况下使用中介者模式 :
一组对象以定义良好但是复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解。
一个对象引用其他很多对象并且直接与这些对象通信 ,导致难以复用该对象。
想定制一个分布在多个类中的行为,而又不想生成太多的子类。
结构
中介者(Mediator):中介者定义一个接口用于与各同事(Colleague)对象通信。
具体中介者(ConcreteMediator):
具体中介者通过协调各同事对象实现协作行为。
了解并维护它的各个同事。
同事(Colleage):定义了一个接口,用于与中介者进行通信。通常包括一个发送消息的方法,以及一个接收消息的方法。
具体同事(ConcreteColleague):实现了同事接口,是真正参与到交互中的对象。它会将自己的消息发送给中介者,由中介者转发给其他同事对象。
协作
同事向一个中介者对象发送和接收请求。中介者在各同事间适当地转发请求以实现协作行为。
效果
优点
减少了子类。Mediator将原本分布于多个对象间的行为集中在一起,改变这些行为只需生成Meditator的子类即可,这样各个Colleague类可被重用。
将各Colleague解耦。Mediator有利于各Colleague间的松耦合,可以独立的改变和复用各Colleague类和Mediator类,Coleague之间符合迪米特法则。
它简化了对象协议。用Mediator和各Colleague间的一对多的交互来代替多对多的交互,一对多的关系更易于理解、维护和扩展。
它对对象如何协作进行了抽象。将中介作为一个独立的概念并将其封装在一个对象中,将注意力从对象各自本身的行为转移到它们之间的交互上来。这有助于弄清楚一个系统中的对象是如何交互的。
提高系统的灵活性。中介者模式使得系统中的对象(同事类对象)可以独立地被复用,因为它们不再依赖于其他对象(内部引用的具体实例)的具体实现。
打个比方:没有中介者的时候,假设有类A,它有个对象引用B是接口或者某个有子类的对象,当其他地方调用A的时候,就要确定引用B的具体实例是B1还是B2,所以这种情况类A就依赖于引用B的具体实现;当使用中介者模式后,类A不再保持有引用B,引用B放在中介者中,不用引用B的时候直接使用类A的对象,要用引用B的时候通过中介者进行调用,引用B具体使用什么实例交给中介者去判定,这样就提高了系统的灵活性(实际上是将复杂度转移到中介者了),这样做的好处一是集中了指定引用B具体实例的操作,二是简化了A的结构,使A用起来更丝滑。
缺点
它使控制集中化。中介者模式将交互的复杂性变为中介者的复杂性。因为中介者封装了协议,它可能变得比任一个Colleague都复杂,这可能使得中介者自身成为一个难于维护的庞然大物。
单点故障。由于所有的交互都通过中介者来进行,一旦中介者对象出现故障,整个系统可能会受到影响。
性能影响。中介者的引入可能会增加一些额外的性能开销,因为所有的请求都需要经过中介者来转发。
可测试性降低。中介者模式使得对象之间的交互变得更加间接,这可能会使得单元测试变得更加困难,因为需要模拟中介者的行为。
实现
忽略抽象的Mediator类。当各Colleague仅与一个Mediator一起工作时,没有必要定义一个抽象的Mediator类,Mediator类提供的抽象耦合已经使各Colleague可与不同的Mediator子类一起工作,反之亦然。
Colleague—Mediator通信。当一个感兴趣的事件发生时,Colleague必须与其Mediator通信。一种实现方法是使用观察者模式,将Mediator实现为一个Observer,各Colleague作为Subject,一旦其状态改变就发送通知给Mediator。Mediator作出的响应是将状态改变的结果传播给其他的Colleague。
另一个方法是在Mediator中定义一个特殊的通知接口,各Colleague在通信时直接调用该接口。当与Mediator通信时,Colleague将自身作为一个参数传递给Mediator,使其可以识别发送者。
应用
问题
当我们想要租房子的时候,首先去找到中介,中介再给我们找到合适的房源,这个过程中有三个角色分别是:租客、中介、房东,为什么能产生联系呢?是因为租客和房东拥有中介的联系方式,而中介又拥有租客和房东的联系方式,这就是最典型的中介模式。从结构图我们可以看出来,具体同事拥有中介的对象引用,中介拥有具体同事的引用,当具体同事之间想要通信时,具体同事对象A调用自己对象内的中介对象,中介对象再调用对应的具体同事对象B,实现A到B之间的通信。
示例
UML
代码示例
抽象中介者:中介
package com.ysj.part5.mediator.mediator;
import com.ysj.part5.mediator.colleague.Person;
/**
* 中介者:中介
*/
public abstract class Mediator {
/**
* 联系某人
* @param message
* @param person
*/
public abstract void constact(String message, Person person);
}
具体中介者:小王,实现中介,
package com.ysj.part5.mediator.concreteMediator;
import com.ysj.part5.mediator.colleague.Person;
import com.ysj.part5.mediator.concreteColleague.HouseOwner;
import com.ysj.part5.mediator.concreteColleague.Tenant;
import com.ysj.part5.mediator.mediator.Mediator;
import lombok.Data;
/**
* 具体中介:小王
*/
@Data
public class XiaoWang extends Mediator {
/**
* 具体同事:房主
*/
private HouseOwner houseOwner;
/**
* 具体同事:租客
*/
private Tenant tenant;
public void constact(String message, Person person) {
if (person == houseOwner) { //房主获取信息
tenant.getMessage(message);
} else { //租客
houseOwner.getMessage(message);
}
}
}
同事:人,同事类也可以不要
package com.ysj.part5.mediator.colleague;
import com.ysj.part5.mediator.mediator.Mediator;
/**
* 同事:人
*/
public abstract class Person {
/**
* 姓名
*/
protected String name;
/**
* 中介者:中介
*/
protected Mediator mediator;
public Person(String name, Mediator mediator) {
this.name = name;
this.mediator = mediator;
}
}
具体同事:房主
package com.ysj.part5.mediator.concreteColleague;
import com.ysj.part5.mediator.colleague.Person;
import com.ysj.part5.mediator.mediator.Mediator;
/**
* 具体同事类:房主
*/
public class HouseOwner extends Person {
public HouseOwner(String name, Mediator mediator) {
super(name, mediator);
}
/**
* @param message
* @return void
* @desc 与中介者联系
*/
public void constact(String message) {
mediator.constact(message, this);
}
/**
* @param message
* @return void
* @desc 获取信息
*/
public void getMessage(String message) {
System.out.println("房主[" + name + "]获得信息:" + message);
}
}
具体同事:租客
package com.ysj.part5.mediator.concreteColleague;
import com.ysj.part5.mediator.colleague.Person;
import com.ysj.part5.mediator.mediator.Mediator;
/**
* 具体同事:租客
*/
public class Tenant extends Person {
public Tenant(String name, Mediator mediator) {
super(name, mediator);
}
/**
* @desc 与中介者联系
* @param message
* @return void
*/
public void constact(String message){
mediator.constact(message, this);
}
/**
* @desc 获取信息
* @param message
* @return void
*/
public void getMessage(String message){
System.out.println("租房者[" + name +"]获得信息:" + message);
}
}
客户端:客户端
package com.ysj.part5.mediator;
import com.ysj.part5.mediator.concreteColleague.HouseOwner;
import com.ysj.part5.mediator.concreteColleague.Tenant;
import com.ysj.part5.mediator.concreteMediator.XiaoWang;
/**
* 中介者模式
* 用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互
*/
public class Client {
public static void main(String[] args) {
//一个房主、一个租房者、一个中介机构
XiaoWang mediator = new XiaoWang();
//房主和租房者只需要知道中介机构即可
HouseOwner houseOwner = new HouseOwner("张三", mediator);
Tenant tenant = new Tenant("李四", mediator);
//中介结构要知道房主和租房者
mediator.setHouseOwner(houseOwner);
mediator.setTenant(tenant);
//租客和房客调用“与中介者联系”的方法,中介者将对方的话进行转接
tenant.constact("听说你那里有三室的房主出租.....");
houseOwner.constact("是的!请问你需要租吗?");
}
}
已知应用
Java Swing/AWT
事件分发模型:Java Swing/AWT 使用中介者模式来处理事件分发,EventQueue 作为中介者,负责接收和分发事件给相应的组件。
Spring Framework
Spring MVC DispatcherServlet:Spring MVC 中的 DispatcherServlet 作为中介者,负责接收 HTTP 请求并分发给相应的控制器。
评论区