1.1 世界需要和平
"你想呀,国与国之间的关系,就类似于不同的对象与对象之间的关系,这就要求对象之间需要知道其他所有对象,尽管将一个系统分割成许多对象通常可以增加其可复用性,但是对象间相互连接的激增又会降低其可复用性了。你知道为什么会这样?"
"我想是因为大量的连接使得一个对象不可能在没有其他对象的支持下工作,系统表现为一个不可分割的整体,所以,对系统的行为进行任何较大的改动就十分困难了。"
"总结得很好嘛,要解决这样的问题,可以应用什么原则?"
"我记得之前讲过的叫'迪米特法则',如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。在这里,你的意思就是说,国与国之间完全可以通过'联合国'这个中介者来发生关系,而不用直接通信。"
"是呀,通过中介者对象,可以将系统的网状结构变成以中介者为中心的星状结构,每个具体对象不再通过直接的联系与另一个对象发生相互作用,而是通过'中介者'对象与另一个对象发生相互作用。中介者对象的设计,使得系统的结构不会因为新对象的引入造成大量的修改工作。"
"当时你对我解释'迪米特法则'的时候,是以我们公司的IT部门的管理为例子的,其实让我一个刚进公司的人去求任何一个不认识的IT部同事帮忙是有困难的,但如果是有IT主管来协调工作,就不至于发生我第一天上班却没有电脑进行工作的局面。IT主管就是一个'中介者'对象了。"
1.2 中介者模式
中介者模式(Mediator),用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。[DP]
中介者模式(Mediator)结构图
package code.chapter25.mediator0;
public class Test {
public static void main(String[] args) {
System.out.println("**********************************************");
System.out.println("《大话设计模式》代码样例");
System.out.println();
ConcreteMediator m = new ConcreteMediator();
ConcreteColleague1 c1 = new ConcreteColleague1(m);
ConcreteColleague2 c2 = new ConcreteColleague2(m);
m.setColleague1(c1);
m.setColleague2(c2);
c1.send("吃过饭了吗?");
c2.send("没有呢,你打算请客?");
System.out.println();
System.out.println("**********************************************");
}
}
//中介者类
abstract class Mediator{
//定义一个抽象的发送消息方法,得到同事对象和发送信息
public abstract void send(String message,Colleague colleague);
}
abstract class Colleague {
protected Mediator mediator;
//构造方法,得到中介者对象
public Colleague(Mediator mediator){
this.mediator = mediator;
}
}
class ConcreteColleague1 extends Colleague {
public ConcreteColleague1(Mediator mediator) {
super(mediator);
}
public void send(String message) {
this.mediator.send(message, this);
}
public void notify(String message) {
System.out.println("同事1得到信息:" + message);
}
}
class ConcreteColleague2 extends Colleague {
public ConcreteColleague2(Mediator mediator) {
super(mediator);
}
public void send(String message)
{
this.mediator.send(message, this);
}
public void notify(String message){
System.out.println("同事2得到信息:" + message);
}
}
class ConcreteMediator extends Mediator{
private ConcreteColleague1 colleague1;
private ConcreteColleague2 colleague2;
public void setColleague1(ConcreteColleague1 value) {
this.colleague1 = value;
}
public void setColleague2(ConcreteColleague2 value) {
this.colleague2 = value;
}
public void send(String message, Colleague colleague)
{
if (colleague == colleague1) {
colleague2.notify(message);
}
else {
colleague1.notify(message);
}
}
}
"Colleague叫作抽象同事类,而ConcreteColleague是具体同事类,每个具体同事只知道自己的行为,而不了解其他同事类的情况,但他们却都认识中介者对象,Mediator是抽象中介者,定义了同事对象到中介者对象的接口,ConcreteMediator是具体中介者对象,实现抽象类的方法,它需要知道所有具体同事类,并从具体同事接收消息,向具体同事对象发出命令。"
Colleague类:抽象同事类。
ConcreteColleague1和ConcreteColleague2等各种同事对象:
Mediator类:抽象中介者类。
ConcreteMediator类:具体中介者类。
"由于有了Mediator,使得ConcreteColleague1和ConcreteColleague2在发送消息和接收信息时其实是通过中介者来完成的,这就减少了它们之间的耦合度了。"大鸟说,"好了,该你来练习了,需求是美国和伊拉克之间的对话都是通过联合国安理会作为中介来完成。"
"哦,这应该没什么大问题,美国和伊拉克都是国家,有一个国家抽象类和两个具体国家类就可以了。但'联合国'到底是Mediator还是ConcreteMediator呢?"
"这要取决于未来是否有可能扩展中介者对象,比如你觉得联合国除了安理会,还有没有可能有其他机构存在呢?"
"联合国的机构还有如国际劳工组织、教科文组织、世界卫生组织、世界贸易组织等,很多的,所以Mediator应该是'联合国机构',而'安理会'是一个具体的中介者。"
"很好,如果不存在扩展情况,那么Mediator可以与ConcreteMediator合二为一。
1.3 安理会作中介
package code.chapter25.mediator1;
public class Test {
public static void main(String[] args) {
System.out.println("**********************************************");
System.out.println("《大话设计模式》代码样例");
System.out.println();
UnitedNationsSecurityCouncil UNSC = new UnitedNationsSecurityCouncil();
USA c1 = new USA(UNSC);
Iraq c2 = new Iraq(UNSC);
UNSC.setUSA(c1);
UNSC.setIraq(c2);
c1.declare("不准研制核武器,否则要发动战争!");
c2.declare("我们没有核武器,也不怕侵略。");
System.out.println();
System.out.println("**********************************************");
}
}
abstract class Country {
protected UnitedNations unitedNations;
public Country(UnitedNations unitedNations){
this.unitedNations = unitedNations;
}
}
class USA extends Country {
public USA(UnitedNations unitedNations) {
super(unitedNations);
}
public void declare(String message) {
this.unitedNations.declare(message, this);
}
public void getMessage(String message) {
System.out.println("美国获得对方信息:" + message);
}
}
class Iraq extends Country {
public Iraq(UnitedNations unitedNations) {
super(unitedNations);
}
public void declare(String message) {
this.unitedNations.declare(message, this);
}
public void getMessage(String message) {
System.out.println("伊拉克获得对方信息:" + message);
}
}
//中介者类
abstract class UnitedNations{
//声明
public abstract void declare(String message,Country country);
}
//联合国安理会
class UnitedNationsSecurityCouncil extends UnitedNations{
private USA countryUSA;
private Iraq countryIraq;
public void setUSA(USA value) {
this.countryUSA = value;
}
public void setIraq(Iraq value) {
this.countryIraq = value;
}
public void declare(String message, Country country)
{
if (country == this.countryUSA) {
this.countryIraq.getMessage(message);
}
else if (country == this.countryIraq) {
this.countryUSA.getMessage(message);
}
}
}
"我觉得尽管这样的设计可以减少了ConcreteColleague类之间的耦合,但这又使得ConcreteMediator责任太多了,如果它出了问题,则整个系统都会有问题了。"
1.4 中介者的优缺点
"说得好,如果联合国安理会出了问题,当然会对世界都造成影响。所以说,中介者模式很容易在系统中应用,也很容易在系统中误用。当系统出现了'多对多'交互复杂的对象群时,不要急于使用中介者模式,而要先反思你的系统在设计上是不是合理。你来总结一下中介者模式的优缺点吧。"
"我觉得中介者模式的优点首先是Mediator的出现减少了各个Colleague的耦合,使得可以独立地改变和复用各个Colleague类和Mediator,比如任何国家的改变不会影响到其他国家,而只是与安理会发生变化。其次,由于把对象如何协作进行了抽象,将中介作为一个独立的概念并将其封装在一个对象中,这样关注的对象就从对象各自本身的行为转移到它们之间的交互上来,也就是站在一个更宏观的角度去看待系统。比如巴以冲突,本来只能算是国与国之间的矛盾,因此各自的看法可能都比较狭隘,但站在联合国安理会的角度,就可以从全球化、也更客观的角度来看待这个问题,在调停和维和上做出贡献。"
"用中介者模式的确可以从更宏观的角度来看待问题。那中介者模式的缺点呢?"
"就是你刚才提到的,具体中介者类ConcreteMediator会因为ConcreteColleague越来越多,而变得非常复杂,反而不容易维护了。"
"是的,由于ConcreteMediator控制了集中化,于是就把交互复杂性变为中介者的复杂性,这就使得中介者会变得比任何一个ConcreteColleague都复杂。事实上,联合国安理会秘书长的工作应该是非常繁忙的,谁叫他就是'全球最大的官'呢。也正因为此,中介者模式的优点来自集中控制,其缺点也是它,使用时要考虑清楚哦。"
"你平时用.NET写的Windows应用程序中的Form或Web网站程序的aspx就是典型的中介者呀。"
"比如计算器程序,它上面有菜单控件、文本控件、多个按钮控件和一个Form窗体,每个控件之间的通信都是通过谁来完成的?它们之间是否知道对方的存在?"
"哦,我知道了,每个控件的类代码都被封装了,所以它们的实例是不会知道其他控件对象的存在的,比如单击数字按钮要在文本框中显示数字,按照我以前的想法就应该要在Button类中编写给TextBox类实例的Text属性赋值的代码,造成两个类有耦合,这显然是非常不合理的。但实际情况是它们都有事件机制,而事件的执行都是在Form窗体的代码中完成,也就是说,所有的控件交互都是由Form窗体来作中介,操作各个对象,这的确是典型的中介者模式应用。"
"中介者模式一般应用于一组对象以定义良好但是复杂的方式进行通信的场合,比如刚才得到的窗体Form对象或Web页面aspx,以及想定制一个分布在多个类中的行为,而又不想生成太多的子类的场合。"
"我相信如果所有的国际安全问题都上升到安理会来解决,世界将不再有战争,世界将会永远和平。让世界充满爱,世界呼唤和平。"