我是荔园微风,作为一名在IT界整整25年的老兵,今天总结一下Windows环境下如何编程实现中介者模式(设计模式)。
不知道大家有没有这样的感觉,看了一大堆编程和设计模式的书,却还是很难理解设计模式,无从下手。为什么?因为你看的都是理论书籍。
我今天就在Windows操作系统上安装好JAVA的IDE编程工具,并用JAVA语言来实现一个中介者模式,真实的实现一个,你看懂代码后,自然就明白了。
中介者模式Mediator Pattern (行为型设计模式)
定义:定义一个对象来封装一系列对象的交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
上面定义听懂了吗?莫名其妙看不懂对吧。所以我们还是来看看实现生活中的例子。
某软件公司推出一款知识社区问答软件,已经成为很多人学习、工作和生活的一部分。在社区的用户沟通中,一般有两种方式:第一种是用户与用户直接私信沟通,第二种是通过社区群进行沟通,一个用户如果要与别的用户沟通或发送文件,通常需要加其他用户为好友,用户与用户之间存在多对多的联系,这将导致系统中用户之间的关系非常复杂,一个用户如果要将相同的问答信息或文件发送给其他所有用户,必须一个一个的发送,于是社区群产生了,如果使用社区群,一个用户就可以向群内的多个用户发送相同的信息和文件而无须一个一个发送,只需要将信息或文件发送到群中或作为群共享即可,群的作用就是将发送者所发送的信息和文件转发给每一个接收者用户。通过引入社区群的机制,将极大减少系统中用户之间的两两通信,用户与用户之间的联系可以通过社区群来实现。
在这些软件中,某些类/对象之间的相互调用关系错综复杂,类似社区用户之间的关系,此时,我们特别需要一个类似社区群一样的中间类来协调这些类/对象之间的复杂关系,以降低系统的耦合度。如何解决这个问题,那就是本文将要介绍的中介者模式。
如果在一个系统中对象之间的联系呈现为网状结构,对象之间存在大量的多对多联系,将导致系统非常复杂,这些对象既会影响别的对象,也会被别的对象所影响,它们之间通过彼此的相互作用实现系统的行为。在网状结构中,几乎每个对象都需要与其他对象发生相互作用,而这种相互作用表现为一个对象与另外一个对象的直接耦合,这将导致一个过度耦合的系统。
中介者模式可以使对象之间的关系数量急剧减少,通过引入中介者对象,可以将系统的网状结构变成以中介者为中心的星形结构,在这个星形结构中,对象不再直接与另一个对象联系,它通过中介者对象与另一个对象发生相互作用。中介者对象的存在保证了对象结构上的稳定,也就是说,系统的结构不会因为新对象的引入带来大量的修改工作。
如果在一个系统中对象之间存在多对多的相互关系,我们可以将对象之间的一些交互行为从各个对象中分离出来,并集中封装在一个中介者对象中,并由该中介者进行统一协调,这样对象之间多对多的复杂关系就转化为相对简单的一对多关系。
在中介者模式中,我们引入了用于协调其他对象/类之间相互调用的中介者类,为了让系统具有更好的灵活性和可扩展性,通常还提供了抽象中介者,其结构图如图所示:
在中介者模式结构图中包含如下几个角色:Mediator(抽象中介者):它定义一个接口,该接口用于与各对象之间进行通信。ConcreteMediator(具体中介者):它是抽象中介者的子类,通过协调各个对象来实现协作行为,它维持了对各个对象的引用。Colleague(抽象类):它定义各个类公有的方法,并声明了一些抽象方法来供子类实现,同时它维持了一个对抽象中介者类的引用,其子类可以通过该引用来与中介者通信。ConcreteColleague(具体类):它是抽象类的子类;每一个对象在需要和其他对象通信时,先与中介者通信,通过中介者来间接完成与其他类的通信;在具体类中实现了在抽象类中声明的抽象方法。
中介者模式的核心在于中介者类的引入,在中介者模式中,中介者类承担了两方面的职责:
(1) 中转作用(结构性):通过中介者提供的中转作用,各个对象就不再需要显式引用其他同事,当需要和其他对象进行通信时,可通过中介者来实现间接调用。该中转作用属于中介者在结构上的支持。
(2) 协调作用(行为性):中介者可以更进一步的对对象之间的关系进行封装,对象可以一致的和中介者进行交互,而不需要指明中介者需要具体怎么做,中介者根据封装在自身内部的协调逻辑,对对象的请求进行进一步处理,将对象成员之间的关系行为进行分离和封装。该协调作用属于中介者在行为上的支持。
在中介者模式中,典型的抽象中介者类代码如下所示:
public abstract class Mediator {
protected ArrayList<Colleague> colleagues=new ArrayList<Colleague>(); //存储对象
//注册方法,用于增加对象
public void register(Colleague colleague) {
colleagues.add(colleague);
}
//声明抽象的业务方法
public abstract void operation();
}
在抽象中介者中可以定义一个类的集合,用于存储对象并提供注册方法,同时声明了具体中介者类所具有的方法。在具体中介者类中将实现这些抽象方法,具体中介者类代码如下所示:
public class ConcreteMediator extends Mediator {
//实现业务方法,封装调用
public void operation() {
......
((Colleague)(colleagues.get(0))).method1(); //通过中介者调用类的方法
......
}
}
在具体中介者类中将调用类的方法,调用时可以增加一些自己的业务代码对调用进行控制。在抽象类中维持了一个抽象中介者的引用,用于调用中介者的方法,典型的抽象类代码如下所示:
public abstract class Colleague {
protected Mediator mediator; //维持一个抽象中介者的引用
public Colleague(Mediator mediator) {
this.mediator=mediator;
}
public abstract void method1(); //声明自身方法,处理自己的行为
//定义依赖方法,与中介者进行通信
public void method2() {
mediator.operation();
}
}
在抽象类中声明了类的抽象方法,而在具体类中将实现这些方法,典型的具体类代码如下所示:
public class ConcreteColleague extends Colleague {
public ConcreteColleague(Mediator mediator) {
super(mediator);
}
//实现自身方法
public void method1() {
......
}
}
在具体类ConcreteColleague中实现了在抽象类中声明的方法,其中方法method1()是类的自身方法(Self-Method),用于处理自己的行为,而方法method2()是依赖方法(Depend-Method),用于调用在中介者中定义的方法,依赖中介者来完成相应的行为,例如调用另一个类的相关方法。
应用实例
下面来看一个具体例子,市公共资源交易中心的大厅里放着一个机器人,可以让工作人员进行操作的机器,上面的软件可以控制今天进厂交易的企业和排序,一旦工作人员打入交易内容,便会在大厅的电子大屏上显示出来。对于系统中存放在交易企业名称,可以通过机器人的控制面板上的各种按钮灵活的进行增删改查。
Component充当抽象类,机器人控制面板上的Button、List、ComboBox和TextBox充当具体类,Mediator充当抽象中介者类,ConcreteMediator充当具体中介者类,ConcreteMediator维持了对具体类的引用,为了简化ConcreteMediator类的代码,我们在其中只定义了一个Button对象和一个TextBox对象。
(1)Mediator(抽象中介者):
package designpatterns.mediator;
public abstract class Mediator {
public abstract void componentChanged(Component c);
}
(2)ConcreteMediator(具体中介者):
package designpatterns.mediator;
public 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();
}
}
}
(3)Colleague(抽象类):
package designpatterns.mediator;
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();
}
(4)ConcreteColleague(具体类):
package designpatterns.mediator;
//按钮类:具体类
public class Button extends Component {
public void update() {
//按钮不产生交互
}
}
//列表框类:具体类
public class List extends Component {
public void update() {
System.out.println("列表框增加一项:A企业。");
}
public void select() {
System.out.println("列表框选中项:B企业。");
}
}
//组合框类:具体类
public class ComboBox extends Component {
public void update() {
System.out.println("组合框增加一项:A企业。");
}
public void select() {
System.out.println("组合框选中项:B企业。");
}
}
//文本框类:具体类
public class TextBox extends Component {
public void update() {
System.out.println("文本框清空。");
}
public void setText() {
System.out.println("文本框显示:A企业。");
}
}
(5)Client(客户端):
package designpatterns.mediator;
public class Client {
public static void main(String args[]) {
//定义中介者对象
ConcreteMediator mediator;
mediator = new ConcreteMediator();
//定义对象
Button adde = new Button();
List list = new List();
ComboBox cb = new ComboBox();
TextBox tb = new TextBox();
adde.setMediator(mediator);
list.setMediator(mediator);
cb.setMediator(mediator);
tb.setMediator(mediator);
mediator.addButton = adde;
mediator.list = list;
mediator.cb = cb;
mediator.userNameTextBox = tb;
adde.changed();
list.changed();
}
}
中介者模式将一个网状的系统结构变成一个以中介者对象为中心的星形结构,在这个星型结构中,使用中介者对象与其他对象的一对多关系来取代原有对象之间的多对多关系。中介者模式在事件驱动类软件中应用较为广泛,特别是基于GUI(Graphical User Interface,图形用户界面)的应用软件,此外,在类与类之间存在错综复杂的关联关系的系统中,中介者模式都能得到较好的应用。
各位小伙伴,这次我们就说到这里,下次我们再深入研究windows环境下的各类设计模式实现。
作者简介:荔园微风,1981年生,高级工程师,浙大工学硕士,软件工程项目主管,做过程序员、软件设计师、系统架构师,早期的Windows程序员,Visual Studio忠实用户,C/C++使用者,是一位在计算机界学习、拼搏、奋斗了25年的老将,经历了UNIX时代、桌面WIN32时代、Web应用时代、云计算时代、手机安卓时代、大数据时代、ICT时代、AI深度学习时代、智能机器时代,我不知道未来还会有什么时代,只记得这一路走来,充满着艰辛与收获,愿同大家一起走下去,充满希望的走下去。