Java设计模式-中介者模式
中介者(Mediator)模式,在23种设计模式中属于对象行为型模式。
用一个中介对象封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
模式介绍
在平常开发的业务场景中,可能会遇到多个对象交叉引用的情况,而且这些对象之间的行为还相互影响。各个对象之间的交互犹如一张蜘蛛网一样,一个对象的行为会影响其它一个或多个对象,同样的,自己也会被其它对象的操作影响,牵一发而动全身。整个业务耦合极高,代码可读性非常低,也不利于后续功能的扩展和维护。
中介者模式可以解决多个对象交叉引用的情况,通过引入一个中介者,它可以使对象之间的关联关系急剧减少,让对象之间的调用关系更加清晰。《重构改善既有代码的设计》一书中有如下描述:
计算机是这样一门科学:它相信所有的问题都可以通过增加一个间接层来解决。
在代码重构时,很多情况下都会引入一个间接层,中介者模式就可以理解为在多个对象交互时引入了一个间接层。
适用性
- 系统对象之间存在复杂的引用关系,且结构混乱难以理解。
- 一个对象引用了许多其它对象且直接与这些对象通信,导致难以复用该对象。
- 想通过一个中间类封装多个类的行为,而又不想生成太多子类。
示例介绍
示例很简单,就是展示一个简单的GUI界面交互行为,界面上面有按钮、文本输入框、组合框和下拉列表。
按钮行为可以影响其它所有组件,下拉列表可以影响组合框和文本输入框,组合框可以影响下拉列表和文本输入框。
// 抽象中介者 public abstract class Mediator { public abstract void componentChanaged(Component c); } // 抽象组件类:抽象同事 public abstract class Component { private Mediator mediator; public Component(Mediator mediator) { this.mediator = mediator; } public void chanaged(){ mediator.componentChanaged(this); } public abstract void onHandleClickEvent(); } // 具体组件下拉列表:具体同事类 public class ListView extends Component{ public ListView(Mediator mediator) { super(mediator); } @Override public void onHandleClickEvent() { System.out.println("列表增加一项:List_BBB"); } public void select(){ System.out.println("列表选中一项:List_AAA"); } } // 具体中介者 public class ConcreteMediator extends Mediator { // 维持对各个同事对象的引用-具体组件 public Button btn; public ListView listView; public ComboBox comboBox; public TextField textField; @Override public void componentChanaged(Component c) { if(c==btn){ System.out.println("--------单击增加按钮-------"); listView.onHandleClickEvent(); comboBox.onHandleClickEvent(); textField.onHandleClickEvent(); }else if(c==listView){ System.out.println("--------列表框选择-------"); comboBox.select(); textField.setText(); }else if(c==comboBox){ System.out.println("--------组合框选择-------"); listView.select(); textField.setText(); } } } // 测试类 public class Client { public static void main(String[] args) { ConcreteMediator mediator=new ConcreteMediator(); Button btn=new Button(mediator); ListView listView=new ListView(mediator); ComboBox comboBox=new ComboBox(mediator); TextField textField=new TextField(mediator); mediator.btn=btn; mediator.listView=listView; mediator.comboBox=comboBox; mediator.textField=textField; btn.chanaged(); System.out.println("---------------------------"); listView.chanaged(); } }
代码运行结果如下:
--------单击增加按钮------- 列表增加一项:List_BBB 组合框增加一项:Combo_BBB 添加 Text_BBB 成功,清空文本框 --------------------------- --------列表框选择------- 组合框选中一项:Combo_AAA 设置文本:Text_AAA
模式分析
中介者模式类图如下:
- Mediator抽象中介者:抽象一个接口,用于各同事(Colleague)对象之间通信。
- ConcreteMediator具体中介者:协调各个同事(Colleague)对象来实现协作行为,它维持了对各个同事对象的引用。
- Colleague抽象同事类:定义了各同事类的公共方法,并提供了一些抽象方法供子类实现,通时维护了一个抽象中介者类的引用,其子类可以通过该引用来与中介者通信。
- ConcreteColleague具体同事类:每一个同事对象在需要和其他同事对象通信时,先与中介者通信,通过中介者来间接完成与其他同事类的通信;在具体同事类中实现了在抽象同事类中声明的抽象方法。
中介者模式的核心在于中介者类的介入,中介者一般承担两方面的职责:
在结构上的中转作用:引入中介者后,各同事之间不再显式引用其它同事,当需要与其它同事通信时,通过中介者间接调用。
在行为上的协调作用:各同事之间一致通过中介者进行交互,中介者根据封装在自身内部的逻辑,对各同事之间的请求进一步处理,将同事之间的逻辑进行了隔离和封装。
模式优点
将各同事对象之间进行了解耦,中介者有利于同事之间的松耦合,可以独立地改变每一个同事和中介者。
简化了对象之间的交互行为,将对象之间的多对多的关系转换为一对多,一对多关系更容易维护和扩展,将原本难以理解的网状结构转换成了相对加单的星型结构。
将控制集中化,它将各对象之间的交互关系集中到了一个中介者类中。
减少了子类的产生,中介者将原本分布于多个对象间的行为集中在一起,改变这些行为只需生成新的中介者子类即可,这使各个同事类可被重用,无须对同事类进行扩展。
模式缺点
中介者类中封装了各个对象之间交互的细节,可能会导致中介者类非常复杂,最终可能使系统难以维护。
与其它模式对比
门面模式(Facade)与中介者的不同之处在于它是对一个对象子系统进行抽象,从而提供了一个更为方便的接口。它的协议是单向的,即Facade 对象对这个子系统类提出请求,但反之则不行。
中介者对象和同事对象之间可以通过观察者模式进行交互通信,中介者模式在GUI软件开发中非常常见,GUI一般都是基于事件订阅完成的,者中事件订阅模式本身就是观察者模式的一种变体。
小结
中介者模式用于协调多个对象之间的调用关系,在基于事件驱动的软件开发中比较常用,特别是基于GUI的软件。
当然了,一般涉及交互对象比较少时,可能不必引入一个中介者,这样反而使代码逻辑看上去更清晰。但是,学习了中介者模式,至少给我们在平常开发中提供了一些启发,软件开发中可以适当的增加一些中间层,中间层的作用不仅限于协调中转,还能起到很好的适配作用。如果我们接入第三方接口,适当增加一层中间层用于适配这些接口,将来一旦三方接口有变,只需要更改一下这个中间层代码即可,而不必在整个工程中一个个修改代码文件。
示例源代码下载,提取码:4895