1、智能家庭项目

1)智能家庭包括各种设备,闹钟、咖啡机、电视机、窗帘等

2)主人要看电视时,各个设备可以协同工作,自动完成看电视的准备工作,比如流程为:闹钟响起->咖啡机开始做咖啡->窗帘自动落下->电视机开始播放

2、传统方案

2.1 设计方案(类图)

efap5

2.2 问题分析

1)当各电器对象有多种状态改变时,相互之间的调用关系会比较复杂

2)各个电器对象彼此联系,你中有我,我中有你,不利于松耦合

3)各个电器对象之间所传递的消息(参数),容易混乱

4)当系统增加一个新的电器对象时,或者执行流程改变时,代码的可维护性、扩展性都不理想 => 考虑中介者模式

3、中介者模式

3.1 基本介绍

1)中介者模式(Mediator Pattern),用一个中介对象来封装一系列的对象交互。中介者使各个对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变他们之间的交互

2)中介者模式属于行为型模式,使代码易于维护

3)比如 MVC 模式,C(Controller 控制器)是 M(Model 模型)和 V(View 视图)的中介者,在前后端交互时起到了中间人的作用

3.2 原理类图

zve13

说明(角色和职责):

1)Mediator 就是抽象中介者,定义了同事对象到中介者对象的接口

2)Colleague 是抽象同事类

3)ConcreteMediator 具体的中介者对象,实现抽象方法,他需要知道所有的具体的同事类,即以一个集合来管理 HashMap,并接受某个同事对象消息,完成相应的任务

4)ConcreteColleague 具体的同事类,会有很多,每个同事只知道自己的行为,而不了解其他同事类的行为(方法),但是他们都依赖中介者对象

3.3 应用实例

1)要求

完成前面的智能家庭的项目,使用中介者模式

2)思路分析和图解(类图)

s1du8

中介者模式-智能家庭的操作流程

  1. 创建 ConcreteMediator 对象
  2. 创建各个同事类对象,比如:Alarm、CoffeeMachine、TV...
  3. 在创建同事类对象的时候,就直接通过构造器,加入到 colleagueMap
  4. 同事类对象,可以调用 sendMessage,最终会去调用 ConcreteMediator 的 getMessage 方法
  5. getMessage 会根据接收到的同事对象发出的消息来协调调用其他的同事对象,完成任务
  6. 可以看到 getMessage 是核心方法,完成相应任务

3)代码实现

Colleague 同事抽象类

package com.wenze.design.mediator;  
  
import lombok.AllArgsConstructor;  
import lombok.Getter;  
  
/**  
 * 同事抽象类  
 *  
 * @author wenze  
 * @version 1.0  
 * @Date 2023-11-07 15:32:01  
 * @since 1.0  
 */
@AllArgsConstructor  
public abstract class Colleague {  
    @Getter  
    public Mediator mediator;  
    public String name;  
    public abstract void sendMessage(int stateChange);  
}

Mediator 抽象中介者

package com.wenze.design.mediator;  
  
/**  
 * 抽象中介者  
 *  
 * @author wenze  
 * @version 1.0  
 * @Date 2023-11-07 15:33:45  
 * @since 1.0  
 */
public abstract class Mediator {  
    public abstract void register(String colleagueName, Colleague colleague);  
    public abstract void getMessage(int stateChange, String colleagueName);  
    public abstract void sendMessage();  
}

Alarm 闹钟

package com.wenze.design.mediator;  
  
/**  
 * 闹钟,具体的同事类  
 *  
 * @author wenze  
 * @version 1.0  
 * @Date 2023-11-07 15:35:38  
 * @since 1.0  
 */
public class Alarm extends Colleague {  
    public Alarm(Mediator mediator, String name) {  
        super(mediator, name);  
        // 在创建 Alarm 同事对象时,将自己放入到 ConcreteMediator 对象集合中  
        mediator.register(name, this);  
    }  
    public void sendAlarm(int stateChange) {  
        sendMessage(stateChange);  
    }  
    @Override  
    public void sendMessage(final int stateChange) {  
        this.getMediator().getMessage(stateChange, this.name);  
    }  
}

CoffeeMachine 咖啡机

package com.wenze.design.mediator;  
  
/**  
 * 咖啡机,具体的同事类  
 *  
 * @author wenze  
 * @version 1.0  
 * @Date 2023-11-07 15:48:43  
 * @since 1.0  
 */
public class CoffeeMachine extends Colleague {  
    public CoffeeMachine(Mediator mediator, String name) {  
        super(mediator, name);  
        mediator.register(name, this);  
    }  
    @Override  
    public void sendMessage(final int stateChange) {  
        this.getMediator().getMessage(stateChange, this.name);  
    }  
    public void startCoffee() {  
        System.out.println("[coffee] coffee machine starting ~");  
    }  
    public void finishCoffee(){  
        System.out.println("[coffee] wait 5 min ~");  
        System.out.println("[coffee] coffee machine finished ~");  
        sendMessage(0);  
    }  
}

TV 电视机

package com.wenze.design.mediator;  
  
/**  
 * 电视机,具体的同事类  
 *  
 * @author wenze  
 * @version 1.0  
 * @Date 2023-11-07 15:41:37  
 * @since 1.0  
 */
public class TV extends Colleague {  
    public TV(Mediator mediator, String name) {  
        super(mediator, name);  
        // 在创建 TV 同事对象时,将自己放入到 ConcreteMediator 对象集合中  
        mediator.register(name, this);  
    }  
    @Override  
    public void sendMessage(final int stateChange) {  
        this.getMediator().getMessage(stateChange, this.name);  
    }  
    public void startTv() {  
        System.out.println("[TV] It's time to start TV !");  
    }  
    public void stopTv() {  
        System.out.println("[TV] It's time to stop TV !");  
    }  
}

Curtains 窗帘

package com.wenze.design.mediator;  
  
/**  
 * 窗帘,具体的同事类  
 *  
 * @author wenze  
 * @version 1.0  
 * @Date 2023-11-07 15:39:56  
 * @since 1.0  
 */
public class Curtains extends Colleague {  
    public Curtains(Mediator mediator, String name) {  
        super(mediator, name);  
        // 在创建Curtains同事对象时,将自己放入到 ConcreteMediator 对象集合中  
        mediator.register(name, this);  
    }    
    @Override  
    public void sendMessage(final int stateChange) {  
        this.getMediator().getMessage(stateChange, this.name);  
    } 
    public void upCurtains() {  
        System.out.println("[curtains] I'm holding up contains !");  
    } 
}

ConcreteMediator 具体的中介者

package com.wenze.design.mediator;  
  
import java.util.HashMap;  
  
/**  
 * 具体的中介者  
 *  
 * @author wenze  
 * @version 1.0  
 * @Date 2023-11-07 15:45:20  
 * @since 1.0  
 */
public class ConcreteMediator extends Mediator {  
    private HashMap<String, Colleague> colleagueMap;  
    private HashMap<String, String> interMap;  
    public ConcreteMediator() {  
        colleagueMap = new HashMap<>();  
        interMap = new HashMap<>();  
    }  
    @Override  
    public void register(final String colleagueName, final Colleague colleague) {  
        colleagueMap.put(colleagueName, colleague);  
        if (colleague instanceof Alarm) {  
            interMap.put("Alarm", colleagueName);  
        } else if (colleague instanceof CoffeeMachine) {  
            interMap.put("CoffeeMachine", colleagueName);  
        } else if (colleague instanceof TV) {  
            interMap.put("TV", colleagueName);  
        } else if (colleague instanceof Curtains) {  
            interMap.put("Curtains", colleagueName);  
        }  
    }  
    @Override  
    public void getMessage(final int stateChange, final String colleagueName) {  
        if (colleagueMap.get(colleagueName) instanceof Alarm) {  
            if (0 == stateChange) {  
                ((CoffeeMachine) (colleagueMap.get(interMap.get("CoffeeMachine")))).startCoffee();  
                ((TV) (colleagueMap.get(interMap.get("TV")))).startTv();  
            } else if (1 == stateChange) {  
                ((TV) (colleagueMap.get(interMap.get("TV")))).stopTv();  
            }  
        } else if (colleagueMap.get(colleagueName) instanceof CoffeeMachine) {  
            ((Curtains) (colleagueMap.get(interMap.get("Curtains")))).upCurtains();  
        } else if (colleagueMap.get(colleagueName) instanceof TV) {  
            // 如果是 TV 发出的消息,这里处理  
        } else if (colleagueMap.get(colleagueName) instanceof Curtains) {  
            // 如果是 窗帘 发出的消息,这里处理  
        }  
    }  
    @Override  
    public void sendMessage() {}
}

Client 客户端

package com.wenze.design.mediator;  
  
/**  
 * 客户端  
 *  
 * @author wenze  
 * @version 1.0  
 * @Date 2023-11-07 15:57:10  
 * @since 1.0  
 */
public class Client {  
    public static void main(String[] args) {  
        // 创建一个中介者对象  
        Mediator mediator = new ConcreteMediator();  
        // 创建 Alarm,并且添加到了 ConcreteMediator 对象的 HashMap 中  
        Alarm alarm = new Alarm(mediator, "alarm");  
        // 创建 CoffeeMachine,并且添加
        CoffeeMachine coffeeMachine = new CoffeeMachine(mediator, "coffeeMachine");  
        // 创建 Curtains,并且添加
        Curtains curtains = new Curtains(mediator, "curtains");  
        // 创建 TV,并且添加
        TV tv = new TV(mediator, "TV");  
        // 让闹钟发出消息  
        alarm.sendAlarm(0);  
        // 咖啡机发出消息  
        coffeeMachine.finishCoffee();  
        // 闹钟继续发出消息
        alarm.sendAlarm(1);  
    }  
}

4、中介者模式的注意事项和细节

1)多个类相互耦合,会形成网状结构,使用中介者模式将网状结构分离为星型结构,进行解耦

2)减少类间依赖,降低了耦合,符合迪米特法则

3)中介者承担了较多的责任,一旦中介者出现了问题,整个系统就会受到影响

4)如果设计不当,中介者对象本身变得过于复杂,这点在实际使用时,要特别注意