解耦多个对象之间的复杂交互:中介者模式

写在前面

在软件设计中,中介者模式是一种解决多模块间交互问题的经典策略。这篇文章深入浅出地介绍了中介者模式的原理、应用场景以及如何在实际项目中实施这一设计模式。无论你是前端工程师、后端开发者还是架构师,都能从中获得启发,提升你的编程技能和系统设计能力,现在让我们一起来探索中介者模式的奥秘吧!

什么是中介者模式

中介者模式是一种软件设计模式,它允许定义一个中间对象(中介者),来协调一组对象之间的交互。通过将一组对象之间的交互抽象化到一个单独的对象中,使得各个对象不必直接交互,而只与中介者发生交互,从而使原本复杂的多对多的关系变成相对简单的单对单或一对多的关系。

中介者模式的核心原理

中介者模式的目的是通过引入中介者来简化对象之间的复杂交互,将多对多的复杂关系转化为相对简单的一对多关系。中介者的职责是进行结构性中转作用和协调行为。结构性中转作用是指各个同事对象不再需要显式地引用其他同事,当需要和其他同事进行通信时,可通过中介者来实现间接调用。协调行为是指中介者可以更进一步地对同事之间的关系进行封装,同事可以一致地和中介者进行交互,而不需要指明中介者需要具体怎么做,中介者根据封装在自身内部的协调逻辑对同事的请求进行进一步处理。

中介者模式(Mediator Pattern)包含以下四个核心角色:

  1. Mediator(抽象中介者):用来定义参与者与中介者之间的交互方式,如同事角色的注册、注销、消息的转发。
  2. ConcreteMediator(具体中介者):实现抽象中介者接口,实现具体交互方式。
  3. Colleague(抽象同事角色):抽象类或者接口,定义参与者如何进行交互,如发送消息、接收消息等。
  4. ConcreteColleague(具体同事角色):实现Colleague中的方法,定义具体行为。
java 复制代码
// 抽象中介者  
public abstract class Mediator {
    public abstract void register(Colleague colleague);
    public abstract void relay(Colleague cl); //转发
}
java 复制代码
public class ConcreteMediator extends Mediator {
    private List<Colleague> colleagues = new ArrayList<Colleague>();
    public void register(Colleague colleague) {
        if (!colleagues.contains(colleague)) {
            colleagues.add(colleague);
            colleague.setMedium(this);
        }
    }
    public void relay(Colleague cl) {
        for (Colleague ob : colleagues) {
            if (!ob.equals(cl)) {
                ((Colleague) ob).receive();
            }
        }
    }
}
csharp 复制代码
//抽象同事类
public abstract class Colleague {
    protected Mediator mediator;
    public void setMedium(Mediator mediator) {
        this.mediator = mediator;
    }
    public abstract void receive();
    public abstract void send();
}
java 复制代码
//具体同事类
public class ConcreteColleague1 extends Colleague {
    public void receive() {
        System.out.println("具体同事类1收到请求。");
    }
    public void send() {
        System.out.println("具体同事类1发出请求。");
        mediator.relay(this); //请中介者转发
    }
}
java 复制代码
//具体同事类
class ConcreteColleague2 extends Colleague {
    public void receive() {
        System.out.println("具体同事类2收到请求。");
    }
    public void send() {
        System.out.println("具体同事类2发出请求。");
        mediator.relay(this); //请中介者转发
    }
}
java 复制代码
public class MediatorPattern {
    public static void main(String[] args) {
        Mediator md = new ConcreteMediator();
        Colleague c1, c2;
        c1 = new ConcreteColleague1();
        c2 = new ConcreteColleague2();
        md.register(c1);
        md.register(c2);
        c1.send();
        System.out.println("-------------");
        c2.send();
    }
}

中介者模式如何实现

需求描述

通过上面的介绍,相信对中介者模式已经有了一个大概的印象了,这里再模拟一个业务场景来重点理解一下,中介者模式中各角色之间是如何交互的.

以前在农村的村部都会有一个大喇叭,上级有什么通知啥的、或者是谁家有个啥喜事都是通过个大喇叭通知给全体村民的,这里的大喇叭实际上就相当于一个中介者的角色,村长可以用来通知上级的重要指示,其他村民也可用来通知自己的喜事.如果使用中介者模式写一段程序来模拟这个过程,应该怎么实现呢?

实现方法

1、声明一个抽象的喇叭接口,即抽象中介者角色,定义两个抽象方法:注册喇叭的使用者、播放消息;

java 复制代码
/**
 * 抽象喇叭
 */
public interface Horn {
    /**
     * 注册使用者
     * @param villager
     */
    void register(Villager villager);

    /**
     * 播放消息
     * @param msg
     */
    void play(Villager villager,String msg);
}

2、声明一个具体的喇叭类,即具体的中介者角色,实现抽象喇叭接口,实现其中定义的抽象方法;

java 复制代码
/**
 * 具体的喇叭
 */
public class ConcreteHorn implements Horn{
    private List<Villager> list=new ArrayList<>();

    @Override
    public void register(Villager villager) {
        list.add(villager);
        villager.setHorn(this);
    }

    @Override
    public void play(Villager villager,String msg) {
        for (Villager obj : list) {
            if (!obj.equals(villager)) {
                obj.receive(msg);
            }
        }
    }
}

3、声明一个抽象的村民类,即抽象同事类,每一个村民都有权利使用喇叭,因此在抽象村民类内部定义一个喇叭属性,另外定义两个抽象方法:用于接受其他村民发的消息和自己向其他村民发消息;

java 复制代码
/**
 * 抽象村民
 */
public abstract class Villager {
    protected Horn horn;

    public void setHorn(Horn horn) {
        this.horn = horn;
    }

    /**
     * 发消息
     * @param msg
     */
    public abstract void send(String msg);

    /**
     * 收到消息
     * @param msg
     */
    public abstract void receive(String msg);
}

4、声明具体的村民类,即具体的同事类,这里声明两个作为村民代表,一个是村长类,另一个是村民代表张三类,继承抽象的村民类,并实现抽象村民类中的两个抽象方法;

java 复制代码
/**
 * 村长
 */
public class VillageHead extends Villager{
    @Override
    public void send(String msg) {
        this.horn.play(this,msg);
    }

    @Override
    public void receive(String msg) {
        System.out.println("村长收到消息:"+msg);
    }
}
java 复制代码
/**
 * 张三
 */
public class ZhangSan extends Villager{
    @Override
    public void send(String msg) {
        this.horn.play(this,msg);
    }

    @Override
    public void receive(String msg) {
        System.out.println("张三收到消息:"+msg);
    }
}
java 复制代码
/**
 * 其他村民
 */
public class OtherVillager extends Villager{
    @Override
    public void send(String msg) {
        this.horn.play(this,msg);
    }

    @Override
    public void receive(String msg) {
        System.out.println("其他村民收到消息:"+msg);
    }
}

5、编写客户端业务,模拟村长给村民发送上级通知、和张三给其他村民发布喜讯通知;

java 复制代码
public class Client {
    public static void main(String[] args) {
        Horn horn=new ConcreteHorn();
        Villager zhangsan=new ZhangSan();
        Villager otherVillager=new OtherVillager();
        Villager villageHead=new VillageHead();
        horn.register(zhangsan);
        horn.register(otherVillager);
        horn.register(villageHead);
        zhangsan.send("大家好,俺是村东头张三!俺娃考上县城第一中学了,晚上都到我家喝酒!");
        System.out.println("-------------");
        villageHead.send("各位村民注意了!上级调配的种子化肥已到村部,各家速来领取!");
    }
}

如何扩展

生活水平提高了,村里喇叭年久失修,也不太好用了,于是村民一致支持在村头广场上建个LED大屏,用途和以前的喇叭一样,也是用来方便传递消息,晚上还插放个新闻联播。怎么实现呢?很简单重新定义LED类,实现抽象喇叭接口,然后再调整一个客户端业务就可以了;这样村里就有两套传递消息的机制了,互不影响;

java 复制代码
public class LED implements Horn{
    private List<Villager> list=new ArrayList<>();
    @Override
    public void register(Villager villager) {
        this.list.add(villager);
        villager.setHorn(this);
    }

    @Override
    public void play(Villager villager, String msg) {
        for (Villager obj : list) {
            if (!obj.equals(villager)) {
                obj.receive(msg);
            }
        }
    }
}
java 复制代码
public class Client {
    public static void main(String[] args) {
        Villager zhangsan=new ZhangSan();
        Villager otherVillager=new OtherVillager();
        Villager villageHead=new VillageHead();
        Horn horn=new LED();
        horn.register(zhangsan);
        horn.register(otherVillager);
        horn.register(villageHead);
        villageHead.send("村民们注意了!村里新修的大屏今天正式投入使用了,晚上放电影,铁道游击队!");
    }
}

那么如果村里有新村民迁入了,应该怎么扩展,是不是也很简单了?

中介者模式适用哪些场景

中介者模式适用于具有以下特征的业务场景:

  • 多个对象之间存在着复杂的关联和交互关系,使得系统难以理解和维护;
  • 需要通过一个中间对象来封装多个对象之间的交互,以提高代码的可读性和可维护性;
  • 在系统中需要频繁地添加、删除或改变对象之间的交互关系,而中介者可以更好地管理和控制这些变化;
  • 需要在多个对象之间进行协调和通信,但是又不希望它们直接进行交互,以免产生复杂的耦合关系。

中介者模式的优点和缺点

中介者模式的优点在于:

  • 能够减少类之间的依赖关系,实现类之间的解耦;
  • 中介者可以统一管理类之间的交互规则,方便修改和扩展;
  • 当一组对象之间的交互很复杂的时候,中介者模式能够简化这些交互,使之变得清晰明了。
  • 中介者对象可能会变得非常复杂,因为它需要管理所有相关类的交互;
  • 中介者对象的变更可能会影响到所有的相关类,这可能会增加系统的风险;
  • 如果不恰当使用中介者模式,可能会导致系统的设计变得更加复杂。

然而,中介者模式也有一些缺点:

  • 中介者对象可能会变得非常复杂,因为它需要管理所有相关类的交互;
  • 中介者对象的变更可能会影响到所有的相关类,这可能会增加系统的风险;
  • 如果不恰当使用中介者模式,可能会导致系统的设计变得更加复杂。

总之,中介者模式是作为一种软件设计模式,它的目的是将一组对象之间的交互抽象化到一个单独的对象中,使得各个对象不必直接交互,而只与这个中间对象发生交互。这种模式可以帮助我们减少类之间的依赖关系,实现类之间的解耦,并简化复杂的交互关系。

写在最后

感谢您阅读这篇关于中介者模式的技术文章!如果您觉得这篇文章对您有帮助,别忘了点赞和收藏哦!这样您就能随时回顾这篇文章,并与您的同事和朋友分享其中的知识和见解。如果您对中介者模式还有更多问题或建议,欢迎在评论区留言,一起探讨和交流!再次感谢您的阅读,祝您工作顺利!

相关推荐
Q_19284999065 分钟前
基于Spring Boot的九州美食城商户一体化系统
java·spring boot·后端
张国荣家的弟弟23 分钟前
【Yonghong 企业日常问题 06】上传的文件不在白名单,修改allow.jar.digest属性添加允许上传的文件SH256值?
java·jar·bi
ZSYP-S34 分钟前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
越甲八千39 分钟前
重温设计模式--享元模式
设计模式·享元模式
yuanbenshidiaos41 分钟前
C++----------函数的调用机制
java·c++·算法
是小崔啊1 小时前
开源轮子 - EasyExcel01(核心api)
java·开发语言·开源·excel·阿里巴巴
黄公子学安全1 小时前
Java的基础概念(一)
java·开发语言·python
liwulin05061 小时前
【JAVA】Tesseract-OCR截图屏幕指定区域识别0.4.2
java·开发语言·ocr
jackiendsc1 小时前
Java的垃圾回收机制介绍、工作原理、算法及分析调优
java·开发语言·算法
Yuan_o_1 小时前
Linux 基本使用和程序部署
java·linux·运维·服务器·数据库·后端