1. 程式人生 > 其它 >【設計模式從入門到精通】17-中介者模式

【設計模式從入門到精通】17-中介者模式

中介者模式

筆記來源:尚矽谷Java設計模式(圖解+框架原始碼剖析)

目錄

中介者模式

1、智慧家庭管理問題

智慧家庭專案:

  • 1)智慧家庭包括各種裝置,鬧鐘、咖啡機、電視機、窗簾等

  • 2)主人要看電視時,各個裝置可以協同工作,自動完成看電視的準備工作,比如流程為:

    鬧鈴響起 => 咖啡機開始做咖啡 => 窗簾自動落下 => 電視機開始播放

傳統方案解決智慧家庭管理問題

傳統方式問題分析

  • 1)當各電器物件有多種狀態改變時,相互之間的呼叫關係會比較複雜
  • 2)各個電器物件彼此聯絡,你中有我,我中有你,不利於鬆耦合
  • 3)各個電器物件之間所傳遞的訊息(引數),容易混亂
  • 4)當系統增加一個新的電器物件時,或者執行流程改變時,程式碼的可維護性、擴充套件性都不理想→考慮中介者模式

2、中介者模式

  • 1)中介者模式(Mediator Pattern),用一箇中介物件來封裝一系列的物件互動。中介者使各個物件不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立地改變它們之間的互動
  • 2)中介者模式屬於行為型模式,使程式碼易於維護
  • 3)比如 MVC 模式,C(Controller控制器)是M(Model模型)和V(View檢視)的中介者,在前後端互動時起到了中間人的作用

原理類圖

中介者模式角色及職責

  • Mediator
    【抽象中介者】:定義了同事物件到中介者物件的介面
  • ConcreteMediator【具體的中介者物件】:實現抽象中介者方法,需要知道所有具體的同事類,即以一個集合來管理HashMap,並接受某個同事物件訊息,完成相應的任務
  • Colleague【抽象同事類】
  • ConcreteColleague【具體的同事類】:會有很多,只知道自己的行為,而不瞭解其他同事類的行為(方法),但他們都依賴中介者物件

3、中介者模式解決智慧家庭管理問題

UML 類圖

智慧家庭管理操作流程

  • 1)建立ConcreMediator物件
  • 2)建立各個同事類物件,比如:AlarmCoffeeMachineTV...
  • 3)在建立同事類物件時,直接通過構造器加入到colleagueMap
  • 4)同事類物件可以呼叫sendMessage,最終會去呼叫ConcreteMediatorgetMessage方法
  • 5)getMessage會根據接收到的同事物件發出的訊息,來協調呼叫其它的同事物件,完成任務
  • 6)可以看到getMessage是核心方法,完成相應任務

核心程式碼

抽象中介者

public abstract class Mediator {
    public abstract void registerColleague(Colleague colleague);

    public abstract void getMsg(Integer state, String name);

    public abstract void sendMsg();
}

抽象同事類

public abstract class Colleague {
    private Mediator mediator;

    public Colleague(Mediator mediator) {
        this.mediator = mediator;
    }

    public Mediator getMediator() {
        return this.mediator;
    }

    public void sendMsg(Integer state) {
        this.getMediator().getMsg(state, this.getClass().getSimpleName());
    }
}

具體同事類

/**
 * 鬧鐘
 */
public class Alarm extends Colleague {
    public Alarm(Mediator mediator) {
        super(mediator);
        this.getMediator().registerColleague(this);
    }

    /**
     * 鬧鈴響起
     */
    public void openAlarm() {
        System.out.println(">>>鬧鈴響起");
        try {
            //模擬鬧鈴耗時
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        sendMsg(1);
    }

    /**
     * 鬧鈴關閉
     */
    public void closeAlarm() {
        System.out.println(">>>鬧鈴關閉");
        sendMsg(0);
    }
}
/**
 * 咖啡機
 */
public class CoffeeMachine extends Colleague {
    public CoffeeMachine(Mediator mediator) {
        super(mediator);
        this.getMediator().registerColleague(this);
    }

    /**
     * 煮咖啡
     */
    public void makeCoffee() {
        System.out.println(">>>煮咖啡中...");
        sendMsg(0);
        try {
            //模擬煮咖啡耗時
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 煮咖啡完畢
     */
    public void completeCoffee() {
        System.out.println(">>>咖啡已煮好");
        sendMsg(1);
    }
}
/**
 * 窗簾
 */
public class Curtain extends Colleague {
    public Curtain(Mediator mediator) {
        super(mediator);
        this.getMediator().registerColleague(this);
    }

    /**
     * 拉起窗簾
     */
    public void upCurtain() {
        System.out.println(">>>拉起窗簾...");
        sendMsg(1);
        try {
            //模擬拉起窗簾耗時
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 拉下窗簾
     */
    public void downCurtain() {
        System.out.println(">>>拉下窗簾...");
        sendMsg(0);
        try {
            //模擬拉下窗簾耗時
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
/**
 * 電視機
 */
public class TV extends Colleague {
    public TV(Mediator mediator) {
        super(mediator);
        this.getMediator().registerColleague(this);
    }

    /**
     * 開啟電視
     */
    public void openTV() {
        System.out.println(">>>開啟電視...");
        sendMsg(1);
    }

    /**
     * 關閉電視
     */
    public void closeTV() {
        System.out.println(">>>關閉電視...");
        sendMsg(0);
    }

    /**
     * 切換頻道
     */
    public void switchChannel(Integer state) {
        System.out.println(">>>切換頻道:" + state);
        sendMsg(state);
        try {
            //模擬看電視耗時
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

具體中介者

public class ConcreteMediator extends Mediator {
    private Map<String, Colleague> colleagueMap;

    public ConcreteMediator() {
        this.colleagueMap = new HashMap<>();
    }

    @Override
    public void registerColleague(Colleague colleague) {
        colleagueMap.put(colleague.getClass().getSimpleName(), colleague);
    }

    @Override
    public void getMsg(Integer state, String name) {
        Colleague colleague = colleagueMap.get(name);
        if (colleague instanceof Alarm) {
            dealAlarm(state);
        } else if (colleague instanceof CoffeeMachine) {
            dealCoffeeMachine(state);
        } else if (colleague instanceof Curtain) {
            dealCurtain(state);
        } else if (colleague instanceof TV) {
            dealTV(state);
        }
    }

    /**
     * 鬧鈴響起後操作
     *
     * @param state
     */
    private void dealAlarm(Integer state) {
        if (Integer.valueOf(1).equals(state)) {
            ((Alarm) colleagueMap.get(Alarm.class.getSimpleName())).closeAlarm();
            ((CoffeeMachine) colleagueMap.get(CoffeeMachine.class.getSimpleName())).makeCoffee();
        }
    }

    /**
     * 咖啡機煮咖啡完畢後操作
     *
     * @param state
     */
    private void dealCoffeeMachine(Integer state) {
        if (Integer.valueOf(1).equals(state)) {
            ((Curtain) colleagueMap.get(Curtain.class.getSimpleName())).downCurtain();
        }
    }

    /**
     * 窗簾落下後操作
     *
     * @param state
     */
    private void dealCurtain(Integer state) {
        if (Integer.valueOf(0).equals(state)) {
            TV tv = (TV) colleagueMap.get(TV.class.getSimpleName());
            tv.openTV();
            tv.switchChannel(101);
        }
    }

    /**
     * 電視關閉後操作
     *
     * @param state
     */
    private void dealTV(Integer state) {
        if (Integer.valueOf(0).equals(state)) {
            ((Curtain) colleagueMap.get(Curtain.class.getSimpleName())).upCurtain();
        }
    }

    @Override
    public void sendMsg() {
        // Do Nothing...
    }
}

測試程式碼

//建立中介者
Mediator mediator = new ConcreteMediator();

//建立各個同事類,並加入Mediator中介者的Map物件中
Alarm alarm = new Alarm(mediator);
CoffeeMachine coffeeMachine = new CoffeeMachine(mediator);
Curtain curtain = new Curtain(mediator);
TV tv = new TV(mediator);

//鬧鐘響起
alarm.openAlarm();
coffeeMachine.completeCoffee();
tv.closeTV();

//>>>鬧鈴響起
//>>>鬧鈴關閉
//>>>煮咖啡中...
//>>>咖啡已煮好
//>>>拉下窗簾...
//>>>開啟電視...
//>>>切換頻道:101
//>>>關閉電視...
//>>>拉起窗簾...

4、中介者模式的注意事項和細節

優點

  • 1)多個類相互耦合,會形成網狀結構,使用中介者模式將網狀結構分離為星型結構,進行解耦

  • 2)減少類間依賴,降低了耦合,符合迪米特原則

缺點

  • 3)中介者承擔了較多的責任,一旦中介者出現了問題,整個系統就會受到影響

  • 4)如果設計不當,中介者物件本身變得過於複雜,這點在實際使用時,要特別注意