1.场景问题
电脑中如果没有主板,那么就会出现如下图所示的乱成一团的结构。
如果上面的情况发生在软件开发呢?
如果软件开发需要很多模块,难道要每个模块同其他模块各个交互么?那岂不是太不好用么?那么如何简化这种交互呢?跟电脑一样,弄一个中介者就行了。所有的模块跟中介者交互,那么就降低了模块间的耦合性。
2.举一个稍微具体的例子
使用电脑看电影:
首先是光驱读取光盘数据,告诉主板,状态改变
主办得到数据,交给CPU处理
CPU处理完,把数据分为视频和音频,通知主板,它处理完了。
主板去得到CPU处理过后的数据,把数据交给显卡和声卡,然后显示出视频和发出声音。
3.解决方案:中介者模式
3.1中介者定义:
用一个中介对象来封装一系列的对象交互,中介者使得各对象不需要显示的相互引用,从而使其耦合松散,而且可以独立的改变他们之间的交互。这样会有利于对象的修改和维护。
3.2中介者结构图:
4.示例代码如下
4.1同事类的抽象父类(注意是个抽象类)
package demo09.mediator.example1; /** * 同事类的抽象父类 */ public abstract class Colleague { /** * 持有中介者对象,每一个同事类都知道它的中介者对象 */ private Mediator mediator; /** * 构造方法,传入中介者对象 * * @param mediator * 中介者对象 */ public Colleague(Mediator mediator) { this.mediator = mediator; } /** * 获取当前同事类对应的中介者对象 * * @return 对应的中介者对象 */ public Mediator getMediator() { return mediator; } }
4.2同事A注意:是继承奥
package demo09.mediator.example1; /** * 具体的同事类A */ public class ConcreteColleagueA extends Colleague { public ConcreteColleagueA(Mediator mediator) { super(mediator); } /** * 示意方法,执行某些业务功能 */ public void someOperation() { //在需要跟其他同事通信的时候,通知中介者对象 getMediator().changed(this); } }
4.3同事B注意:是继承
package demo09.mediator.example1; /** * 具体的同事类B */ public class ConcreteColleagueB extends Colleague { public ConcreteColleagueB(Mediator mediator) { super(mediator); } /** * 示意方法,执行某些业务功能 */ public void someOperation() { //在需要跟其他同事通信的时候,通知中介者对象 getMediator().changed(this); } }
4.4中介者,定义各个同事对象通信的接口
package demo09.mediator.example1; /** * 中介者,定义各个同事对象通信的接口 */ public interface Mediator { /** * 同事对象在自身改变的时候来通知中介者的方法, * 让中介者去负责相应的与其他同事对象的交互 * @param colleague 同事对象自身,好让中介者对象通过对象实例 * 去获取同事对象的状态 */ public void changed(Colleague colleague); }
4.5具体的中介者实现
所有的同事交互都是在中介者中实现
package demo09.mediator.example1; /** * 具体的中介者实现 */ public class ConcreteMediator implements Mediator { /** * 持有并维护同事A */ private ConcreteColleagueA colleagueA; /** * 持有并维护同事B */ private ConcreteColleagueB colleagueB; /** * 设置中介者需要了解并维护的同事A对象 * @param colleague 同事A对象 */ public void setConcreteColleagueA(ConcreteColleagueA colleague) { colleagueA = colleague; } /** * 设置中介者需要了解并维护的同事B对象 * @param colleague 同事B对象 */ public void setConcreteColleagueB(ConcreteColleagueB colleague) { colleagueB = colleague; } public void changed(Colleague colleague) { //某个同事类发生了变化,通常需要与其他同事交户 //具体协调相应的同事对象来实现协作行为 } }
5.使用中介者实现范例:
5.1结构示意图
5.2同事类的抽象父类(注意:是个抽象类)
package demo09.mediator.example2; /** * 同事类的抽象父类 */ public abstract class Colleague { /** * 持有中介者对象,每一个同事类都知道它的中介者对象 */ private Mediator mediator; /** * 构造方法,传入中介者对象 * @param mediator 中介者对象 */ public Colleague(Mediator mediator) { this.mediator = mediator; } /** * 获取当前同事类对应的中介者对象 * @return 对应的中介者对象 */ public Mediator getMediator() { return mediator; } }
5.3光驱类,一个同事类
package demo09.mediator.example2; /** * 光驱类,一个同事类 */ public class CDDriver extends Colleague{ public CDDriver(Mediator mediator) { super(mediator); } /** * 光驱读取出来的数据 */ private String data = ""; /** * 获取光驱读取出来的数据 * @return 光驱读取出来的数据 */ public String getData(){ return this.data; } /** * 读取光盘 */ public void readCD(){ //逗号前是视频显示的数据,逗号后是声音 this.data = "设计模式,值得好好研究"; //通知主板,自己的状态发生了改变 this.getMediator().changed(this); } }
5.4CPU类,一个同事类
package demo09.mediator.example2; /** * CPU类,一个同事类 */ public class CPU extends Colleague{ public CPU(Mediator mediator) { super(mediator); } /** * 分解出来的视频数据 */ private String videoData = ""; /** * 分解出来的声音数据 */ private String soundData = ""; /** * 获取分解出来的视频数据 * @return 分解出来的视频数据 */ public String getVideoData() { return videoData; } /** * 获取分解出来的声音数据 * @return 分解出来的声音数据 */ public String getSoundData() { return soundData; } /** * 处理数据,把数据分成音频和视频的数据 * @param data 被处理的数据 */ public void executeData(String data){ //把数据分解开,前面的是视频数据,后面的是音频数据 String [] ss = data.split(","); this.videoData = ss[0]; this.soundData = ss[1]; //通知主板,CPU的工作完成 this.getMediator().changed(this); } }
5.5显卡类,一个同事类
package demo09.mediator.example2; /** * 显卡类,一个同事类 */ public class VideoCard extends Colleague { public VideoCard(Mediator mediator) { super(mediator); } /** * 显示视频数据 * * @param data * 被显示的数据 */ public void showData(String data) { System.out.println("您正观看的是:" + data); } }
5.6声卡类,一个同事类
package demo09.mediator.example2; /** * 声卡类,一个同事类 */ public class SoundCard extends Colleague{ public SoundCard(Mediator mediator) { super(mediator); } /** * 按照声频数据发出声音 * @param data 发出声音的数据 */ public void soundData(String data){ System.out.println("画外音:"+data); } }
5.7中介者接口
package demo09.mediator.example2; /** * 中介者对象的接口 */ public interface Mediator { /** * 同事对象在自身改变的时候来通知中介者的方法, * 让中介者去负责相应的与其他同事对象的交互 * @param colleague 同事对象自身,好让中介者对象通过对象实例 * 去获取同事对象的状态 */ public void changed(Colleague colleague); }
5.8主板类,实现中介者接口
package demo09.mediator.example2; /** * 主板类,实现中介者接口 */ public class MotherBoard implements Mediator{ /** * 需要知道要交互的同事类——光驱类 */ private CDDriver cdDriver = null; /** * 需要知道要交互的同事类——CPU类 */ private CPU cpu = null; /** * 需要知道要交互的同事类——显卡类 */ private VideoCard videoCard = null; /** * 需要知道要交互的同事类——声卡类 */ private SoundCard soundCard = null; public void setCdDriver(CDDriver cdDriver) { this.cdDriver = cdDriver; } public void setCpu(CPU cpu) { this.cpu = cpu; } public void setVideoCard(VideoCard videoCard) { this.videoCard = videoCard; } public void setSoundCard(SoundCard soundCard) { this.soundCard = soundCard; } public void changed(Colleague colleague) { if(colleague == cdDriver){ //表示光驱读取数据了 this.opeCDDriverReadData((CDDriver)colleague); }else if(colleague == cpu){ //表示CPU处理完了 this.opeCPU((CPU)colleague); } } /** * 处理光驱读取数据过后与其他对象的交互 * @param cd 光驱同事对象 */ private void opeCDDriverReadData(CDDriver cd){ //1:先获取光驱读取的数据 String data = cd.getData(); //2:把这些数据传递给CPU进行处理 this.cpu.executeData(data); } /** * 处理CPU处理完数据后与其他对象的交互 * @param cpu CPU同事类 */ private void opeCPU(CPU cpu){ //1:先获取CPU处理过后的数据 String videoData = cpu.getVideoData(); String soundData = cpu.getSoundData(); //2:把这些数据传递给显卡和声卡展示出来 this.videoCard.showData(videoData); this.soundCard.soundData(soundData); } }
5.9客户端使用:看电影
package demo09.mediator.example2; public class Client { public static void main(String[] args) { // 1:创建中介者——主板对象 MotherBoard mediator = new MotherBoard(); // 2:创建同事类 CDDriver cd = new CDDriver(mediator); CPU cpu = new CPU(mediator); VideoCard vc = new VideoCard(mediator); SoundCard sc = new SoundCard(mediator); // 3:让中介者知道所有的同事 mediator.setCdDriver(cd); mediator.setCpu(cpu); mediator.setVideoCard(vc); mediator.setSoundCard(sc); // 4:开始看电影,把光盘放入光驱,光驱开始读盘 cd.readCD(); } }
6.思考中介者模式
6.1中介者模式的功能以及调用顺序图:
封装对象之间的交互。同事之间是如下交互的。
6.2中介者模式的本质
封装交互
6.3中介者模式的优缺点
优点:松散耦合,集中控制交互,多对多变成一对多。
缺点:过度集中化,中介者对象变得很复杂,难于管理和维护。