协调多个对象之间的交互 —— 中介者模式

中介者模式可以使对象之间的关系数量急剧减少,通过引入中介者对象,可以将系统的网状 结构变成以中介者为中心的星形结构,如图20-5所示。在这个星形结构中,同事对象不再直接 与另一个对象联系,它通过中介者对象与另一个对象发生相互作用。中介者对象的存在保证 了对象结构上的稳定,也就是说,系统的结构不会因为新对象的引入带来大量的修改工作。

中介者模式定义如下: 中介者模式(Mediator Pattern):用一个中介对象(中介者)来封装一系列的对象交互,中 介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之 间的交互。
在中介者模式中,我们引入了用于协调其他对象/类之间相互调用的中介者类,为了让系统具 有更好的灵活性和可扩展性,通常还提供了抽象中介者,其结构图如图20-6所示:

在中介者模式结构图中包含如下几个角色:
● Mediator(抽象中介者):它定义一个接口,该接口用于与各同事对象之间进行通信。
● ConcreteMediator(具体中介者):它是抽象中介者的子类,通过协调各个同事对象来实现 协作行为,它维持了对各个同事对象的引用。
● Colleague(抽象同事类):它定义各个同事类公有的方法,并声明了一些抽象方法来供子类 实现,同时它维持了一个对抽象中介者类的引用,其子类可以通过该引用来与中介者通信。
● ConcreteColleague(具体同事类):它是抽象同事类的子类;每一个同事对象在需要和其他 同事对象通信时,先与中介者通信,通过中介者来间接完成与其他同事类的通信;在具体同事类中实现了在抽象同事类中声明的抽象方法。
在中介者模式中,典型的抽象中介者类代码如下所示:
abstract class Mediator { protected ArrayList<Colleague> colleagues; //用于存储同事对象 //注册方法,用于增加同事对象 public void register(Colleague colleague) { colleagues.add(colleague); } //声明抽象的业务方法 public abstract void operation(); }
具体中介者类代码如下所示:
//实现业务方法,封装同事之间的调用
public void operation() {
......
((Colleague)(colleagues.get(0))).method1(); //通过中介者调用同事类的方法
......
}
}
在抽象同事类中维持了一个抽象中介者的引用,用于调用中介者的方法,典型的抽象同事类 代码如下所示:
abstract class Colleague { protected Mediator mediator; //维持一个抽象中介者的引用 public Colleague(Mediator mediator) { this.mediator=mediator; } public abstract void method1(); //声明自身方法,处理自己的行为 //定义依赖方法,与中介者进行通信 public void method2() { mediator.operation(); } }
典型的具体同事类代码如下所示:
class ConcreteColleague extends Colleague { public ConcreteColleague(Mediator mediator) { super(mediator); } //实现自身方法 public void method1() { ...... }
//定义依赖方法,与中介者进行通信
public void method2() {
mediator.operation();
}
}
20.3 完整解决方案

公司开发人员通过分析发现,在图20-2中,界面组件之间存在较为复杂的交互关系:如 果删除一个客户,要在客户列表(List)中删掉对应的项,客户选择组合框(ComboBox)中客户名 称也将减少一个;如果增加一个客户信息,客户列表中需增加一个客户,且组合框中也将增 加一项。
如果实现界面组件之间的交互是公司开发人员必须面对的一个问题?公司开发人员对组件之间的交互关系进行了分析,结果如下:
(1) 当用户单击“增加”按钮、“删除”按钮、“修改”按钮或“查询”按钮时,界面左侧的“客户选择 组合框”、“客户列表”以及界面中的文本框将产生响应。
(2) 当用户通过“客户选择组合框”选中某个客户姓名时,“客户列表”和文本框将产生响应。
(3) 当用户通过“客户列表”选中某个客户姓名时,“客户选择组合框”和文本框将产生响应。 于是,Sunny公司开发人员根据组件之间的交互关系绘制了如图20-3所示初始类图:
原方案:

现方案:
为了协调界面组件对象之间的复杂交互关系,Sunny公司开发人员使用中介者模式来设计客户 信息管理窗口,其结构示意图如图20-7所示:


在图20-8中,ConcreteMediator充当具体中介者类,ConcreteMediator维持 了对具体同事类的引用,抽象同事类维持了对抽象中介者的引用。完整代码如下所示:
抽象中介者:
abstract class Mediator { public abstract void componentChanged(Component c); }
具体中介者:
class ConcreteMediator extends Mediator { //维持对各个同事对象的引用 public Button addButton; public List list; public TextBox userNameTextBox; public ComboBox cb; //封装同事对象之间的交互 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(); } } }
抽象同事类:
abstract class Component { protected Mediator mediator; public void setMediator(Mediator mediator) { this.mediator = mediator; } //转发调用 public void changed() { mediator.componentChanged(this); } public abstract void update(); }
具体同事类:
//按钮类:具体同事类 class Button extends Component { public void update() { //按钮不产生交互 } } //列表框类:具体同事类 class List extends Component { public void update() { System.out.println("列表框增加一项:张无忌。"); } public void select() { System.out.println("列表框选中项:小龙女。"); } } //组合框类:具体同事类 class ComboBox extends Component { public void update() { System.out.println("组合框增加一项:张无忌。"); } public void select() { System.out.println("组合框选中项:小龙女。"); } } //文本框类:具体同事类 class TextBox extends Component { public void update() { System.out.println("客户信息增加成功后文本框清空。"); } public void setText() { System.out.println("文本框显示:小龙女。"); } }
编写如下客户端测试代码:
class Client { public static void main(String args[]) { //定义中介者对象 ConcreteMediator mediator; mediator = new ConcreteMediator(); //定义同事对象 Button addBT = new Button(); List list = new List(); ComboBox cb = new ComboBox(); TextBox userNameTB = new TextBox(); 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(); } }
编译并运行程序,输出结果如下:
--单击增加按钮-- 列表框增加一项:张无忌。 组合框增加一项:张无忌。 客户信息增加成功后文本框清空。 ----------------------------- --从列表框选择客户-- 组合框选中项:小龙女。 文本框显示:小龙女。
浙公网安备 33010602011771号