中介模式 (学习笔记2021.09.24)
前言:
中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。中介者模式属于行为型模式。
**意图:**用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
**主要解决:**对象与对象之间存在大量的关联关系,这样势必会导致系统的结构变得很复杂,同时若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应的处理。
**何时使用:**多个类相互耦合,形成了网状结构。
**如何解决:**将上述网状结构分离为星型结构。
**关键代码:**对象 Colleague 之间的通信封装到一个类中单独处理。
应用实例: 1、中国加入 WTO 之前是各个国家相互贸易,结构复杂,现在是各个国家通过 WTO 来互相贸易。 2、MVC 框架,其中C(控制器)就是 M(模型)和 V(视图)的中介者。
优点: 1、降低了类的复杂度,将一对多转化成了一对一。 2、各个类之间的解耦。 3、符合迪米特原则。
**缺点:**中介者会庞大,变得复杂难以维护。
使用场景: 1、系统中对象之间存在比较复杂的引用关系,导致它们之间的依赖关系结构混乱而且难以复用该对象。 2、想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。
**注意事项:**不应当在职责混乱的时候使用。
如果你对中介模式有所了解,你可能会知道,中介模式跟之前讲过的观察者模式有点相似,所以,今天我们还会详细讨论下这两种模式的区别。
中介模式的设计思想跟中间层很像,通过引入中介这个中间层,将一组对象之间的交互关系(或者说依赖关系)从多对多(网状关系)转换为一对多(星状关系)。原来一个对象要跟 n 个对象交互,现在只需要跟一个中介对象交互,从而最小化对象之间的交互关系,降低了代码的复杂度,提高了代码的可读性和可维护性。
前提条件
按照上图的条件与实现方式, 我们来使用中介者模式来实现需求
1.0 创建抽象中介
/**
* 中介者抽象
*/
public interface Mediator {
// 注册交互对象
void register(Component obj);
// components = 所有的需要通过中介来交互的对象, parameter = 交互方法参数
void handleEvent(Class component, String parameter);
}
2.0 具体的实现中介操作行为
/**
* @Author: ZhiHao
* @Date: 2021/9/23 17:39
* @Description: 中介者具体实现, 转发各种组件请求
* @Versions 1.0
**/
public class MediatorImpl implements Mediator {
private final List<Component> componentList = new ArrayList<>(2);
@Override
public void register(Component obj) {
componentList.add(obj);
}
@Override
public void handleEvent(Class component, String parameter) {
componentList.stream()
.filter(component::isInstance)
.findAny()
.ifPresent(obj -> {
if (obj instanceof Alarm) {
System.out.println("MediatorImpl + Alarm");
((Alarm) obj).onEvent(parameter);
}
if (obj instanceof Calendar) {
System.out.println("MediatorImpl + Calendar");
((Calendar) obj).onEvent(parameter);
}
});
}
}
3.0 交互对象抽象类
/**
* @Author: ZhiHao
* @Date: 2021/9/23 17:31
* @Description: 需要通过中介者交互的实现该接口
* @Versions 1.0
**/
public interface Component {
}
4.0 具体交互对象
/**
* @Author: ZhiHao
* @Date: 2021/9/23 17:44
* @Description: 日历
* @Versions 1.0
**/
public class Calendar implements Component {
public void onEvent(String msg){
System.out.println("Calendar执行了"+msg);
}
}
// *--------------------------------------------------
/**
* @Author: ZhiHao
* @Date: 2021/9/23 17:40
* @Description: 闹钟
* @Versions 1.0
**/
public class Alarm implements Component {
public void onEvent(String msg){
System.out.println("Alarm执行了"+msg);
}
}
进行测试
public void applicationTest() throws Exception {
// 交互类
Component alarm = new Alarm();
Component calendar = new Calendar();
// 中介者
Mediator mediator = new MediatorImpl();
// 注册到中介者, 让中介者知道所有的需要交互的对象
mediator.register(alarm);
mediator.register(calendar);
// 然后需要调用, 通过中介调用, Alarm与Calendar进行了解耦
// 调用闹钟 -- 甚至可以判断交互类的状态, 来改变调用顺序
mediator.handleEvent(Alarm.class,"gg");
// 调用日历
mediator.handleEvent(Calendar.class,"eee");
}
// -----------------------------------------------------
Alarm执行了gg
Calendar执行了eee
从代码中我们可以看出,原本业务逻辑会分散在各个控件中,现在都集中到了中介类中。实际上,这样做既有好处,也有坏处。好处是简化了控件之间的交互,坏处是中介类有可能会变成大而复杂的“上帝类”(God Class)。所以,在使用中介模式的时候,我们要根据实际的情况,平衡对象之间交互的复杂度和中介类本身的复杂度。
中介模式和观察者模式的区别在哪里呢?什么时候选择使用中介模式?什么时候选择使用观察者模式呢?
在观察者模式中,尽管一个参与者既可以是观察者,同时也可以是被观察者,但是,大部分情况下,交互关系往往都是单向的,一个参与者要么是观察者,要么是被观察者,不会兼具两种身份。也就是说,在观察者模式的应用场景中,参与者之间的交互关系比较有条理。
而中介模式正好相反。只有当参与者之间的交互关系错综复杂,维护成本很高的时候,我们才考虑使用中介模式。毕竟,中介模式的应用会带来一定的副作用,前面也讲到,它有可能会产生大而复杂的上帝类。除此之外,如果一个参与者状态的改变,其他参与者执行的操作有一定先后顺序的要求,这个时候,中介模式就可以利用中介类,通过先后调用不同参与者的方法,来实现顺序的控制,而观察者模式是无法实现这样的顺序要求的。
1