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中介者模式的優缺點
優點:鬆散耦合,集中控制互動,多對多變成一對多。
缺點:過度集中化,中介者對象變得很複雜,難於管理和維護。