掘金 后端 ( ) • 2024-04-23 10:42

代码GitHub:https://github.com/lanjie6/DesignPattern.git

中介者模式

  • 中介者模式是指定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。
  • 中介者模式又叫调停模式,它是迪米特法则的典型应用。

进一步阐述:

  • 在现实生活中,常常会出现好多对象之间存在复杂的交互关系,这种交互关系常常是“网状结构”,它要求每个对象都必须知道它需要交互的对象。例如:每个人必须记住他(她)所有朋友的电话,而且,朋友中如果有人的电话修改了,他(她)必须让其他所有的朋友一起修改,这叫作“牵一发而动全身”,非常复杂。
  • 如果把这种“网状结构”改为“星形结构”的话,将大大降低它们之间的“耦合性”,这时只要找一个“中介者”就可以了。
  • 如前面所说的“每个人必须记住所有朋友电话”的问题,只要在网上建立一个每个朋友都可以访问的“通信录”就解决了。
  • 这样的例子还有很多,例如:你刚刚参加工作想租房,可以找“房屋中介”,或者自己刚刚到一个陌生城市找工作,可以找“人才交流中心”帮忙。

中介者模式包含四种角色:

  • Mediator(抽象中介者角色):它是中介者的接口,提供了同事对象注册与转发同事对象信息的抽象方法。
  • Concrete Mediator(具体中介者角色):实现中介者接口,定义一个 List 来管理同事对象,协调各个同事角色之间的交互关系,因此它依赖于同事角色。
  • Colleague(抽象同事类角色):定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。
  • Concrete Colleague(具体同事类角色):是抽象同事类的实现者,当需要与其他同事对象交互时,由中介者对象负责后续的交互

案例:以班委员通过班长作为中介者来协调工作为例。其中中介者Mediator接口类就是抽象中介者角色,班长ClassMonitor类就是具体中介者角色,班委员ClassLeader抽象类就是抽象同事类角色,生活委员LifeLeader类、心理委员PsychologicalLeader类、学习委员StudyLeader类就是具体同事类角色。

UML类图:

中介者模式.jpg

客户端Client类:

/**
 * 使用中介者模式的客户端
 */
public class Client {
​
    public static void main(String[] args) {
        Mediator m = new ClassMonitor();
        ClassLeader life = new LifeLeader(m);
        ClassLeader study = new StudyLeader(m);
        ClassLeader psycho = new PsychologicalLeader(m);
        //当前委员发送请求给班长然后通过班长与其他委员通信
        System.out.println("------生活委员->班长->心理委员------");
        life.sendRequest();
        System.out.println("--------------------------");
​
        System.out.println("------学习委员->班长->心理委员,生活委员------");
        study.sendRequest();
        System.out.println("--------------------------");
​
        System.out.println("------心理委员->班长->生活委员------");
        psycho.sendRequest();
    }
}

中介者Mediator接口类

/**
 * 中介者接口类(抽象中介者)
 */
public interface Mediator {
​
    /**
     * 注册班委员
     */
    void register(String name, ClassLeader classLeader);
​
    /**
     * 班长根据班委员名字获得通知请求
     */
    void command(String name);
}

班长ClassMonitor类:

/**
 * 班长(具体中介者角色)
 */
public class ClassMonitor implements Mediator {
​
    //利用map集合存放学委的相关属性
    private Map<String, ClassLeader> map = new HashMap<>();
​
    /**
     * 将对应名称的学委对象进行注册
     */
    @Override
    public void register(String name, ClassLeader classLeader) {
        map.put(name, classLeader);
    }
​
    /**
     * 班长大人获取来自指定学委的请求通知
     */
    @Override
    public void command(String name) {
        map.get(name).job();
    }
}

班委员ClassLeader抽象类:

/**
 * 班委员接口(抽象同事类)
 */
public abstract class ClassLeader {
​
    //持有对中介者的引用
    protected Mediator media;
​
    /**
     * 本职工作
     */
    public abstract void job();
​
    /**
     * 向班长提出请求
     */
    public abstract void sendRequest();
}

生活委员LifeLeader类:

/**
 * 生活委员类(具体同事类)
 */
public class LifeLeader extends ClassLeader {
​
    public LifeLeader(Mediator media) {
        super.media = media;
        media.register("LifeLeader", this);
    }
​
    @Override
    public void job() {
        System.out.println("生活委员->小张最近生活作风有点问题,需要我的帮助!");
    }
​
    @Override
    public void sendRequest() {
        System.out.println("生活委员->小张是不是有什么精神负担,班长大人去叫心理委员去看看什么情况吧!");
        media.command("PsychologicalLeader");
    }
}

心理委员PsychologicalLeader类:

/**
 * 心理委员
 */
public class PsychologicalLeader extends ClassLeader {
​
    public PsychologicalLeader(Mediator media) {
        super.media = media;
        media.register("PsychologicalLeader", this);
    }
​
    @Override
    public void job() {
        System.out.println("心理委员->小张最近心情好像不太好,需要我的帮助!");
    }
​
    @Override
    public void sendRequest() {
        System.out.println("心理委员->小张是不是生活上有什么问题,班长大人叫生活委员多关注一下吧!");
        media.command("LifeLeader");
    }
}

学习委员StudyLeader类:

/**
 * 学习委员
 */
public class StudyLeader extends ClassLeader {
​
    public StudyLeader(Mediator media) {
        super.media = media;
        media.register("StudyLeader", this);
    }
​
    @Override
    public void job() {
        System.out.println("学习委员->小张最近成绩突飞猛进,果然在我的英明指导下没有人能不起飞!");
    }
​
    @Override
    public void sendRequest() {
        System.out.println("学习委员->小张为了成绩居然还搞抄袭,怎么变成这样了?班长大人快去通知生活委员和心理委员看看!");
        media.command("LifeLeader");
        media.command("PsychologicalLeader");
    }
}
​

运行结果:

中介者模式运行结果.png

总结:

  • 类之间各司其职,符合迪米特法则。
  • 降低了对象之间的耦合性,使得对象易于独立地被复用。
  • 将对象间的一对多关联转变为一对一的关联,提高系统的灵活性,使得系统易于维护和扩展。
  • 将原本多个对象直接的相互依赖变成了中介者和多个同事类的依赖关系。当同事类越多时,中介者就会越臃肿,变得复杂且难以维护。

典型运用场景举例:

  • 聊天系统中的网络通信,大部分就是采用的中介者模式。
  • 消息队列中间件就是中介者模式最好的例子之一。