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

评论

您确定要删除吗?删除之后不可恢复