当前位置 博文首页 > xiaokantianse:18.java设计模式之中介者模式

    xiaokantianse:18.java设计模式之中介者模式

    作者:xiaokantianse 时间:2021-01-18 18:06

    基本需求

    • 智能家庭包括各种设备,闹钟、咖啡机、电视机、窗帘等
    • 要看电视时,各个设备可以协同工作,自动完成看电视的准备工作,比如流程为:闹铃响起->咖啡机开始做咖啡->窗帘自动落下->电视机开始播放

    传统方案

    • 各个类之间相互调用,依赖严重,消息传递不准确,调用结构混乱
    • 说明
      • 当各电器对象有多种状态改变时,相互之间的调用关系会比较复杂
      • 各个 电器对象彼此联系,你中有我,我中有你,不利于松耦合
      • 各个电器对象之间所传递的消息(参数),容易混乱
      • 当系统增加一个新的电器对象时,或者执行流程改变时,代码的可维护性、扩展性都不理想 考虑中介者模式

    基本介绍

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

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

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

    • 比如租房子

      • 没有中介:有六个房东需要出租房屋,适合不一样的人租住。这六个房东之间有点联系。这时租客来租房,看了一号房东的房子不满意、但是一号房东觉得可以让他去看看其他五个朋友的房间。然后开始联系五个朋友。进行消息传递。一个如此,另外五个亦如此,如果二号房东房屋不出租或者出租出去了,情况发生了变化。他则需要通知其他五个朋友,告诉他们不用再给他介绍租客。这里就造成了中间一个人发生了变化,需要改动其他五个人
      • 有中介:那六个房东都把房屋交给中介处理。租客A看房间一不满意直接通过中介看房间二。当房间二被出租了。中介也只需要通知房东二号、然后他们签订合同。下次还有人看房间就不会再看房间二。这里一个出现了变化也就影响改变了一个。并不会影响其他另外五个房东
    • UML类图(原理)

      • 说明
        • Mediator 就是抽象中介者,定义了同事对象到中介者对象的接口
        • Colleague 是抽象同事类
        • ConcreteMediator 具体的中介者对象, 实现抽象方法, 他需要知道所有的具体的同事类,即以一个集合来管理HashMap,并接受某个同事对象消息,完成相应的任务
        • ConcreteColleague 具体的同事类,会有很多, 每个同事只知道自己的行为,而不了解其他同事类的行为(方法),但是他们都依赖中介者对象
    • UML类图(案例)

      • 说明
        • ConcreteMediator是中介者实现类
        • 在创建同事实现类的时候通过其构造方法将其注册到中介者中,通过sendMessage方法向中介者发送消息
        • ConcreteMediator的getMessage方法会接收到同事类的消息协调调用其他对象,是核心方法
    • 代码实现

      • public abstract class Mediator {
        
           // 中介者抽象类
        
           // 将同事类加入到中介者中,由中介者对所有同事类进行交互,同事类之间不进行交互
           // 将依赖由网状变成星状
           public abstract void register(String colleagueName, Colleague colleague);
        
           // 接收消息 由同事类发出
           public abstract void getMessage(String colleagueName, int stateChange);
        
           // 发送消息,发给同事类,本次案例中没有用到
           public abstract void sendMessage();
        
        }
        
        // 中介者实现类
        public class ConcreteMediator extends Mediator {
        
           // 使用集合管理所有的中介者,如果key重复,则是最新注册的 ,可否弄成MapList的形式管理重复key
           private Map<String, Colleague> colleagueMap;
        
           // 名称的集合,方便我们自己获取对应的同事类,因为每次注册时 我们并不知道key,想获取value时不能获取,指定名称 后续使用简单
           private Map<String, String> nameMap;
        
           public ConcreteMediator() {
               this.colleagueMap = new HashMap<>();
               this.nameMap = new HashMap<>();
           }
        
           @Override
           public void register(String colleagueName, Colleague colleague) {
               colleagueMap.put(colleagueName, colleague);
               if (colleague instanceof Alarm) {
                   // 自定义名称 方便我们下面使用
                   nameMap.put("alarm", colleagueName);
               } else if (colleague instanceof CoffeeMachine) {
                   nameMap.put("coffeeMachine", colleagueName);
               } else if (colleague instanceof Curtain) {
                   nameMap.put("curtain", colleagueName);
               } else if (colleague instanceof TV) {
                   nameMap.put("tv", colleagueName);
               }
           }
        
           @Override
           public void getMessage(String colleagueName, int stateChange) {
               // 根据得到消息,完成对应任务,中介者在这个方法,协调各个具体的同事对象,完成任务
               if (colleagueMap.get(colleagueName) instanceof Alarm) {
                   // 处理闹钟的消息 可使用中介者的sendMessage方法进行处理
                   if (stateChange == 0) {
                       ((CoffeeMachine) colleagueMap.get(nameMap.get("coffeeMachine"))).startCoffee();
                       ((TV) colleagueMap.get(nameMap.get("tv"))).startTv();
                   } else if (stateChange == 1) {
                       ((TV) colleagueMap.get(nameMap.get("tv"))).stopTv();
                   }
               } else if (colleagueMap.get(colleagueName) instanceof CoffeeMachine) {
                   // 处理咖啡机的消息
                   if (stateChange == 0) {
                       ((Curtain) colleagueMap.get(nameMap.get("curtain"))).upCurtains();
                   }
               } else if (colleagueMap.get(colleagueName) instanceof Curtain) {
                   // 处理窗帘的消息
                   System.out.println();
               } else if (colleagueMap.get(colleagueName) instanceof TV) {
                   // 处理电视机的消息
                   System.out.println();
               }
           }
        
           @Override
           public void sendMessage() {
        
           }
        }
        
      • public abstract class Colleague {
        
           // 同事抽象类
        
           protected String name;
        
           private Mediator mediator;
        
           public Colleague(String name, Mediator mediator) {
               this.name = name;
               this.mediator = mediator;
           }
        
           public Mediator getMediator() {
               return this.mediator;
           }
        
           // 发送消息
           public abstract void sendMessage(int stateChange);
        
        }
        
        // 同事子类一 闹钟类
        public class Alarm extends Colleague {
        
           public Alarm(String name, Mediator mediator) {
               super(name, mediator);
               // 将自己在中介者中进行注册
               mediator.register(name, this);
           }
        
           @Override
           public void sendMessage(int stateChange) {
               // 获取中介者 调用中介者的getMessage方法 将消息传递给中介者 由中介者处理消息
               this.getMediator().getMessage(super.name, stateChange);
           }
        
           public void sendAlarm(int stateChange) {
               sendMessage(stateChange);
           }
        }
        
        
        // 同事子类二 咖啡机
        public class CoffeeMachine extends Colleague {
        
           public CoffeeMachine(String name, Mediator mediator) {
               super(name, mediator);
               mediator.register(name, this);
           }
        
           @Override
           public void sendMessage(int stateChange) {
               this.getMediator().getMessage(super.name, stateChange);
           }
        
           public void startCoffee() {
               System.out.println("It's time to startcoffee!");
           }
        
           public void finishCoffee() {
               System.out.println("After 5 minutes!");
               System.out.println("Coffee is ok!");
               sendMessage(0);
           }
        }
        
        // 同事子类三 窗帘
        public class Curtain extends Colleague {
        
           public Curtain(String name, Mediator mediator) {
               super(name, mediator);
               mediator.register(name, this);
           }
        
           @Override
           public void sendMessage(int stateChange) {
               this.getMediator().getMessage(super.name, stateChange);
           }
        
           public void upCurtains() {
               System.out.println("I am holding Up Curtains!");
           }
        }
        
        // 同事子类四 电视机
        public class TV extends Colleague {
        
           public TV(String name, Mediator mediator) {
               super(name, mediator);
               mediator.register(name, this);
           }
        
           @Override
           public void sendMessage(int stateChange) {
               this.getMediator().getMessage(super.name, stateChange);
           }
        
           public void startTv() {
               System.out.println("It's time to StartTv!");
           }
        
           public void stopTv() {
               System.out.println("Stop Tv!");
           }
        }
        
        
      • public class Client {
           public static void main(String[] args) {
               // 创建中介者
               Mediator concreteMediator = new ConcreteMediator();
               // 创建同事类 并将其注册到中介者中
               Alarm alarm = new Alarm("alarm", concreteMediator);
               CoffeeMachine coffeeMachine = new CoffeeMachine("coffeeMachine", concreteMediator);
               Curtain curtain = new Curtain("curtain", concreteMediator);
               // 注意 此处中介者中的nameMap就起到了作用 我们的名称是TV,而我们中介中使用的tv作为key使用 没有nameMap就会报错 nameMap起到桥梁作用
               TV tv = new TV("TV", concreteMediator);
        
               // 使用alarm发送消息
               alarm.sendAlarm(0);
               coffeeMachine.finishCoffee();
               alarm.sendAlarm(1);
           }
        }
        

    注意事项

    • 多个类相互耦合,会形成网状结构, 使用中介者模式将网状结构分离为星型结构,进行解耦
    • 如果增加一个同事类,直接增加即可,降低了类的复杂度,将一对多转化成了一对一
    • 减少类间依赖,降低了耦合,符合迪米特原则
    • 中介者承担了较多的责任,一旦中介者出现了问题,整个系统就会受到影响
    • 中介者 承担了较多的责任,一旦中介者出现了问题,整个系统就会受到影响
    下一篇:没有了