中介者模式
案例介绍:
编写信息管理模块:
界面组件之间存在较为复杂的交互关系:如果删除一个客户,要在客户列表(List)中删掉对应的项,客户选择组合框(ComboBox)中客户名称也将减少一个;如果增加一个客户信息,客户列表中需增加一个客户,且组合框中也将增加一项。
如果实现界面组件之间的交互一个问题?
(1) 当用户单击“增加”按钮、“删除”按钮、“修改”按钮或“查询”按钮时,界面左侧的“客户选择组合框”、“客户列表”以及界面中的文本框将产生响应。
(2) 当用户通过“客户选择组合框”选中某个客户姓名时,“客户列表”和文本框将产生响应。
(3) 当用户通过“客户列表”选中某个客户姓名时,“客户选择组合框”和文本框将产生响应。
于是开发人员根据组件之间的交互关系绘制了如图20-3所示初始类图:
设计方案存在如下问题:
(1) 系统结构复杂且耦合度高:每一个界面组件都与多个其他组件之间产生相互关联和调用,若一个界面组件对象发生变化,需要跟踪与之有关联的其他所有组件并进行处理,系统组件之间呈现一种较为复杂的网状结构,组件之间的耦合度高。
(2) 组件的可重用性差:由于每一个组件和其他组件之间都具有很强的关联,若没有其他组件的支持,一个组件很难被另一个系统或模块重用,这些组件表现出来更像一个不可分割的整体,而在实际使用时,我们往往需要每一个组件都能够单独重用,而不是重用一个由多个组件组成的复杂结构。
(3) 系统的可扩展性差:如果在上述系统中增加一个新的组件类,则必须修改与之交互的其他组件类的源代码,将导致多个类的源代码需要修改,同样,如果要删除一个组件也存在类似的问题,这违反了“开闭原则”,可扩展性和灵活性欠佳。
由于存在上述问题,Sunny公司开发人员不得不对原有系统进行重构,那如何重构呢?大家想到了“迪米特法则”,引入一个“第三者”来降低现有系统中类之间的耦合度。由这个“第三者”来封装并协调原有组件两两之间复杂的引用关系,使之成为一个松耦合的系统,这个“第三者”又称为“中介者”,中介者模式因此而得名。
你中有我,我中有你,不利于松耦合
中介者模式基本介绍
- 中介者模式(Mediator Pattern),用一个中介对象来封装一系列的对象交互。
中介者使各个对象不需要显式地相互引用,从而使其耦合松散,而且可以独立
地改变它们之间的交互 - 中介者模式属于行为型模式,使代码易于维护
- 比如MVC模式,C(Controller控制器)是M(Model模型)和V(View视图)的中介者,在前后端交互时起到了中间人的作用
对象之间存在大量的多对多联系,将导致系统非常复杂,这些对象既会影响别的对象,也会被别的对象所影响,这些对象称为同事对象,它们之间通过彼此的相互作用实现系统的行为。在网状结构中,几乎每个对象都需要与其他对象发生相互作用,而这种相互作用表现为一个对象与另外一个对象的直接耦合,这将导致一个过度耦合的系统。
中介者模式是“迪米特法则”的一个典型应用。
中介者模式类图:
中介者模式角色:
● Mediator(抽象中介者):它定义一个接口,该接口用于与各同事对象之间进行通信。
● ConcreteMediator(具体中介者):它是抽象中介者的子类,通过协调各个同事对象来实现协作行为,它维持了对各个同事对象的引用。
● Colleague(抽象同事类):它定义各个同事类公有的方法,并声明了一些抽象方法来供子类实现,同时它维持了一个对抽象中介者类的引用,其子类可以通过该引用来与中介者通信。
● ConcreteColleague(具体同事类):它是抽象同事类的子类;每一个同事对象在需要和其他同事对象通信时,先与中介者通信,通过中介者来间接完成与其他同事类的通信;在具体同事类中实现了在抽象同事类中声明的抽象方法。
中介者类承担了两方面的职责:
(1) 中转作用(结构性):通过中介者提供的中转作用,各个同事对象就不再需要显式引用其他同事,当需要和其他同事进行通信时,可通过中介者来实现间接调用。该中转作用属于中介者在结构上的支持。
(2) 协调作用(行为性):中介者可以更进一步的对同事之间的关系进行封装,同事可以一致的和中介者进行交互,而不需要指明中介者需要具体怎么做,中介者根据封装在自身内部的协调逻辑,对同事的请求进行进一步处理,将同事成员之间的关系行为进行分离和封装。该协调作用属于中介者在行为上的支持。
代码实现:
抽象组件类;抽象同事类
`
public abstract class Component {
protected Mediator mediator;
public void setMediator(Mediator mediator) {
this.mediator = mediator;
}
public void changed (){
mediator.componentChanged(this);
}
public abstract void update();
}
具体同事类: 按钮组件
/**
* @author 孙一鸣 on 2020/2/20
*/
public class MyButton extends Component{
@Override
public void update() {
//按钮不产生交互
}
}
具体同事类:组合框类
/**
* 组合框类:具体同事类
* @author 孙一鸣 on 2020/2/20
*/
public class MyComboBox extends Component {
public void update() {
System.out.println("组合框增加一项:比尔盖茨。");
}
public void select() {
System.out.println("组合框选中项:马云");
}
}
具体同事类:列表框类
/**
* 列表框类:具体同事类
* @author 孙一鸣 on 2020/2/20
*/
public class MyList extends Component{
@Override
public void update() {
System.out.println("列表框新加同事:比尔盖茨");
}
public void select (){
System.out.println("列表框选中项:马云");
}
}
具体同事类:文本框类
/**
* //文本框类:具体同事类
*
* @author 孙一鸣 on 2020/2/20
*/
public class MyTextBox extends Component {
public void update() {
System.out.println("客户信息增加成功后文本框清空。");
}
public void setText() {
System.out.println("文本框显示:马云");
}
}
抽象中介者类:
/**
*
//抽象中介者
* @author 孙一鸣 on 2020/2/20
*/
public abstract class Mediator {
public abstract void componentChanged(Component c);
}
具体中介者类:
/**
* 具体中介者
*
* @author 孙一鸣 on 2020/2/20
*/
public class ConcreteMediator extends Mediator{
//维持对多个同事对象的引用
public MyButton addButton;
public MyList list;
public MyTextBox userNameTextBox;
public MyComboBox cb;
//封装同事对象之间的交互
@Override
public void componentChanged(Component c) {
//单击按钮
if(c == addButton) {
System.out.println("--单击增加按钮--");
list.update();
cb.update();
userNameTextBox.update();
}
//从列表框选择客户
else if(c == list) {
System.out.println("--从列表框选择客户--");
cb.select();
userNameTextBox.setText();
}
//从组合框选择客户
else if(c == cb) {
System.out.println("--从组合框选择客户--");
cb.select();
userNameTextBox.setText();
}
}
}
测试类:
/**
* @author 孙一鸣 on 2020/2/20
*/
public class Client {
public static void main(String args[]) {
//定义中介者对象
ConcreteMediator mediator;
mediator = new ConcreteMediator();
//定义同事对象
MyButton addBT = new MyButton();
MyList list = new MyList();
MyComboBox cb = new MyComboBox();
MyTextBox userNameTB = new MyTextBox();
addBT.setMediator(mediator);
list.setMediator(mediator);
cb.setMediator(mediator);
userNameTB.setMediator(mediator);
mediator.addButton = addBT;
mediator.list = list;
mediator.cb = cb;
mediator.userNameTextBox = userNameTB;
addBT.changed();
System.out.println("-----------------------------");
list.changed();
}
}
结果截图:
中介者模式的注意事项和细节
- 多个类相互耦合,会形成网状结构, 使用中介者模式将网状结构分离为星型结构,进行解耦
- 减少类间依赖,降低了耦合,符合迪米特原则
- 中介者承担了较多的责任,一旦中介者出现了问题,整个系统就会受到影响
- 如果设计不当,中介者对象本身变得过于复杂,这点在实际使用时,要特别注意
本文参考链接:https://blog.csdn.net/lovelion/article/details/8483081
版权声明:本文为CSDN博主「LoveLion」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。