MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Java中介者模式的实现与应用

2022-01-165.3k 阅读

中介者模式概述

中介者模式(Mediator Pattern)是一种行为型设计模式,它通过引入一个中介者对象来封装一系列对象之间的交互,使得这些对象之间不再相互直接引用,而是通过中介者进行通信。这样可以降低对象之间的耦合度,提高系统的可维护性和可扩展性。

在现实生活中,中介者模式有很多应用场景。比如在一个机场的空中交通管制系统中,飞机之间并不直接通信决定如何起飞、降落等操作,而是通过塔台(中介者)来协调各个飞机的动作。在一个即时通讯软件中,用户之间的消息传递并非直接点对点,而是通过服务器(中介者)来转发。

Java 中的中介者模式实现结构

  1. 中介者接口(Mediator Interface):定义了各个同事对象(Colleague)之间通信的方法。
  2. 具体中介者(Concrete Mediator):实现中介者接口,协调各个同事对象之间的交互,维护对各个同事对象的引用。
  3. 同事接口(Colleague Interface):定义了同事对象向中介者发送消息以及接收中介者消息的方法。
  4. 具体同事(Concrete Colleague):实现同事接口,持有对中介者对象的引用,通过中介者与其他同事对象进行通信。

代码示例

1. 定义中介者接口

public interface ChatMediator {
    void sendMessage(String msg, User user);
    void addUser(User user);
}

2. 实现具体中介者

import java.util.ArrayList;
import java.util.List;

public class ChatRoom implements ChatMediator {
    private List<User> users = new ArrayList<>();

    @Override
    public void sendMessage(String msg, User user) {
        for (User u : users) {
            if (u != user) {
                u.receive(msg);
            }
        }
    }

    @Override
    public void addUser(User user) {
        users.add(user);
    }
}

3. 定义同事接口

public interface User {
    void send(String msg);
    void receive(String msg);
}

4. 实现具体同事

public class NormalUser implements User {
    private String name;
    private ChatMediator mediator;

    public NormalUser(String name, ChatMediator mediator) {
        this.name = name;
        this.mediator = mediator;
    }

    @Override
    public void send(String msg) {
        System.out.println(this.name + " 发送消息: " + msg);
        mediator.sendMessage(msg, this);
    }

    @Override
    public void receive(String msg) {
        System.out.println(this.name + " 接收消息: " + msg);
    }
}

5. 测试代码

public class MediatorPatternDemo {
    public static void main(String[] args) {
        ChatRoom mediator = new ChatRoom();

        User user1 = new NormalUser("张三", mediator);
        User user2 = new NormalUser("李四", mediator);
        User user3 = new NormalUser("王五", mediator);

        mediator.addUser(user1);
        mediator.addUser(user2);
        mediator.addUser(user3);

        user1.send("大家好啊!");
    }
}

中介者模式在 Java 框架中的应用

  1. Swing 中的事件处理:在 Swing 中,当一个组件(如按钮)产生一个事件(如点击事件)时,并不是直接与其他相关组件进行交互。而是通过事件调度线程(中介者)来处理事件。事件调度线程接收组件产生的事件,并将其分发给注册的监听器(同事对象)进行处理。这样各个组件之间就不需要直接相互引用,降低了耦合度。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class SwingMediatorExample {
    public static void main(String[] args) {
        JFrame frame = new JFrame("Swing 中介者示例");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300, 200);

        JPanel panel = new JPanel();
        panel.setLayout(new FlowLayout());

        JButton button = new JButton("点击我");
        JLabel label = new JLabel("等待点击");

        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                label.setText("按钮被点击了");
            }
        });

        panel.add(button);
        panel.add(label);
        frame.add(panel);
        frame.setVisible(true);
    }
}

在这个例子中,按钮和标签之间并没有直接的引用关系。按钮产生的点击事件通过事件调度线程(中介者)传递给了注册的监听器(这里是一个匿名内部类,充当同事对象),从而实现了对标签文本的更新。

  1. Java EE 中的 EJB(Enterprise JavaBeans):在 EJB 架构中,会话 Bean(Session Bean)、实体 Bean(Entity Bean)等组件之间的交互通常会通过一个 EJB 容器(中介者)来协调。EJB 容器负责管理组件的生命周期、资源分配以及组件之间的通信。各个 EJB 组件不需要直接知道其他组件的具体位置和细节,只需要通过 EJB 容器进行交互。这使得系统的架构更加清晰,组件之间的耦合度降低。

中介者模式的优缺点

  1. 优点
    • 降低耦合度:通过中介者,各个同事对象之间不再直接相互引用,而是通过中介者进行通信,从而降低了对象之间的耦合度。这样当某个同事对象的实现发生变化时,对其他同事对象的影响较小。
    • 提高可维护性和可扩展性:由于耦合度降低,系统的维护和扩展变得更加容易。新增或修改同事对象时,只需要在中介者中进行相应的调整,而不需要在多个同事对象之间进行复杂的修改。
    • 集中控制交互:中介者集中管理了各个同事对象之间的交互逻辑,使得交互逻辑更加清晰和易于理解。这有助于对系统进行调试和优化。
  2. 缺点
    • 中介者可能变得复杂:随着系统中同事对象数量的增加和交互逻辑的复杂化,中介者的实现可能会变得非常复杂,难以维护和理解。
    • 性能问题:所有同事对象之间的通信都通过中介者进行,可能会在高并发场景下成为性能瓶颈。

中介者模式与其他设计模式的关系

  1. 与观察者模式的比较
    • 目的不同:观察者模式主要用于建立一种一对多的依赖关系,当一个对象状态发生变化时,通知所有依赖它的对象。而中介者模式重点在于封装对象之间的交互,使得对象之间间接通信,降低耦合度。
    • 结构不同:在观察者模式中,主题(Subject)和观察者(Observer)之间存在直接的引用关系。而在中介者模式中,同事对象之间不直接引用,而是通过中介者进行通信。
  2. 与外观模式的比较
    • 目的不同:外观模式为子系统提供一个统一的接口,简化子系统的使用。中介者模式主要是用于处理对象之间复杂的交互关系,降低耦合度。
    • 作用范围不同:外观模式通常作用于不同的子系统之间,而中介者模式更多地作用于同一系统内的多个对象之间。

中介者模式的实际应用场景扩展

  1. 游戏开发中的场景管理:在一个多人在线游戏中,不同的游戏角色(玩家控制的角色、NPC 等)之间存在各种交互,比如战斗、交易、对话等。可以使用中介者模式,创建一个场景管理器(中介者)来协调这些角色之间的交互。角色之间不需要直接知道其他角色的具体实现细节,只需要通过场景管理器来进行交互。这样可以方便地添加新的角色类型或者修改现有角色的行为,而不会对其他角色造成太大影响。
// 定义游戏角色接口
public interface GameCharacter {
    void interactWith(GameCharacter other);
    String getName();
}

// 定义具体游戏角色
public class Player implements GameCharacter {
    private String name;
    private GameSceneMediator mediator;

    public Player(String name, GameSceneMediator mediator) {
        this.name = name;
        this.mediator = mediator;
    }

    @Override
    public void interactWith(GameCharacter other) {
        mediator.interact(this, other);
    }

    @Override
    public String getName() {
        return name;
    }
}

// 定义 NPC 角色
public class NPC implements GameCharacter {
    private String name;
    private GameSceneMediator mediator;

    public NPC(String name, GameSceneMediator mediator) {
        this.name = name;
        this.mediator = mediator;
    }

    @Override
    public void interactWith(GameCharacter other) {
        mediator.interact(this, other);
    }

    @Override
    public String getName() {
        return name;
    }
}

// 定义游戏场景中介者
public class GameSceneMediator {
    public void interact(GameCharacter character1, GameCharacter character2) {
        System.out.println(character1.getName() + " 与 " + character2.getName() + " 进行交互");
    }
}

// 测试代码
public class GameMediatorExample {
    public static void main(String[] args) {
        GameSceneMediator mediator = new GameSceneMediator();
        Player player = new Player("玩家 A", mediator);
        NPC npc = new NPC("商人", mediator);

        player.interactWith(npc);
    }
}
  1. 分布式系统中的消息传递:在一个分布式系统中,不同的服务节点之间需要进行消息传递和交互。可以使用中介者模式,引入一个消息代理(中介者)。各个服务节点将消息发送给消息代理,由消息代理负责将消息路由到目标服务节点。这样可以解耦服务节点之间的直接依赖关系,提高系统的可扩展性和灵活性。
import java.util.HashMap;
import java.util.Map;

// 定义服务节点接口
public interface ServiceNode {
    void sendMessage(String message, String targetNodeId);
    void receiveMessage(String message);
    String getNodeId();
}

// 定义具体服务节点
public class ConcreteServiceNode implements ServiceNode {
    private String nodeId;
    private MessageBroker mediator;

    public ConcreteServiceNode(String nodeId, MessageBroker mediator) {
        this.nodeId = nodeId;
        this.mediator = mediator;
    }

    @Override
    public void sendMessage(String message, String targetNodeId) {
        mediator.routeMessage(message, this, targetNodeId);
    }

    @Override
    public void receiveMessage(String message) {
        System.out.println("节点 " + nodeId + " 接收到消息: " + message);
    }

    @Override
    public String getNodeId() {
        return nodeId;
    }
}

// 定义消息代理(中介者)
public class MessageBroker {
    private Map<String, ServiceNode> nodes = new HashMap<>();

    public void registerNode(ServiceNode node) {
        nodes.put(node.getNodeId(), node);
    }

    public void routeMessage(String message, ServiceNode sourceNode, String targetNodeId) {
        ServiceNode targetNode = nodes.get(targetNodeId);
        if (targetNode != null) {
            targetNode.receiveMessage(message);
        } else {
            System.out.println("目标节点 " + targetNodeId + " 不存在");
        }
    }
}

// 测试代码
public class DistributedSystemMediatorExample {
    public static void main(String[] args) {
        MessageBroker broker = new MessageBroker();

        ConcreteServiceNode node1 = new ConcreteServiceNode("node1", broker);
        ConcreteServiceNode node2 = new ConcreteServiceNode("node2", broker);

        broker.registerNode(node1);
        broker.registerNode(node2);

        node1.sendMessage("你好,node2", "node2");
    }
}

如何优化中介者模式的实现

  1. 分层设计中介者:当系统中的交互逻辑非常复杂时,可以考虑对中介者进行分层设计。将不同类型的交互逻辑放在不同层次的中介者中,使得中介者的职责更加清晰,易于维护。例如,在一个大型企业级应用中,可以将业务逻辑相关的交互放在一个高层中介者中,而将数据持久化相关的交互放在一个底层中介者中。
  2. 使用事件驱动机制:结合事件驱动机制来优化中介者的性能。当同事对象发送消息时,中介者可以将这些消息转化为事件,并通过事件队列进行处理。这样可以避免在高并发情况下中介者成为性能瓶颈。同时,还可以使用异步处理机制来进一步提高系统的响应速度。
  3. 引入缓存机制:在中介者中引入缓存机制,对于一些频繁使用的交互结果或者配置信息进行缓存。这样可以减少重复计算和查询,提高系统的性能。例如,在一个电商系统中,中介者在处理商品信息的交互时,可以缓存一些热门商品的基本信息,以加快响应速度。

中介者模式在不同 Java 应用架构中的应用策略

  1. 单体应用:在单体应用中,中介者模式可以有效地管理不同模块之间的交互。比如在一个小型的企业资源规划(ERP)系统中,销售模块、采购模块、库存模块等之间存在复杂的交互。通过引入中介者,可以将这些交互逻辑集中管理,使得各个模块之间的耦合度降低。在实现时,可以将中介者设计为一个单例对象,方便各个模块进行调用。
  2. 微服务架构:在微服务架构中,各个微服务之间的通信和交互可以使用中介者模式。可以将服务注册中心或者消息代理作为中介者。微服务通过向中介者注册自己,并通过中介者来发现其他微服务以及进行消息传递。这样可以解耦微服务之间的直接依赖关系,提高微服务架构的灵活性和可扩展性。同时,为了保证系统的性能和可靠性,需要对中介者进行合理的配置和优化,比如采用分布式缓存、负载均衡等技术。
  3. 移动应用开发:在移动应用开发中,中介者模式可以用于管理不同界面组件之间的交互。例如,在一个社交类移动应用中,用户资料界面、聊天界面、好友列表界面等之间存在交互。可以使用中介者来协调这些界面组件之间的操作,使得界面之间的耦合度降低,提高应用的可维护性和可扩展性。在实现时,可以结合 Android 或 iOS 平台提供的事件机制来实现中介者的功能。

中介者模式在应对业务变化时的灵活性

  1. 新增业务逻辑:当业务需求发生变化,需要新增一些交互逻辑时,由于中介者模式将交互逻辑集中在中介者中,只需要在中介者中添加相应的处理逻辑即可。而不需要对各个同事对象进行大规模的修改。例如,在一个在线教育系统中,原本学生和教师之间只有课程学习相关的交互,现在需要增加作业批改的交互。只需要在中介者中添加处理作业批改交互的方法,并在适当的时候调用,而学生和教师对应的同事类基本不需要修改。
  2. 修改业务逻辑:如果需要修改现有业务逻辑中的交互方式,同样可以在中介者中进行修改。因为同事对象之间不直接进行交互,所以修改中介者中的交互逻辑不会影响到同事对象的内部实现。比如在一个物流配送系统中,原本订单和配送员之间的分配逻辑是按照距离优先,现在需要改为按照配送员的空闲时间优先。只需要在中介者中修改订单分配给配送员的逻辑,而订单和配送员对应的同事类可以保持不变。
  3. 删除业务逻辑:当业务需求变化,需要删除某些交互逻辑时,在中介者中删除相应的处理代码即可。这不会对同事对象的其他功能产生影响。例如,在一个金融交易系统中,原本有一个特定的交易类型之间的交互逻辑,由于业务调整不再需要,直接在中介者中删除相关处理代码,各个交易相关的同事对象依然可以正常工作。

中介者模式与代码复用和可维护性的关系

  1. 代码复用:中介者模式通过将交互逻辑集中在中介者中,提高了代码的复用性。不同的同事对象可以复用中介者中的交互逻辑。例如,在多个不同的业务模块中,如果都存在类似的对象之间的消息传递和协调逻辑,那么可以复用同一个中介者类来处理这些交互,避免了在每个模块中重复编写相似的交互代码。
  2. 可维护性:由于中介者模式降低了对象之间的耦合度,使得代码的可维护性得到提高。当某个同事对象的功能发生变化时,只需要关注该同事对象本身的修改,而对其他同事对象以及整个系统的影响较小。同时,中介者集中管理交互逻辑,使得交互逻辑更加清晰,便于理解和维护。如果需要对交互逻辑进行修改,只需要在中介者中进行操作,而不需要在多个同事对象之间进行复杂的查找和修改。

中介者模式在团队协作开发中的优势

  1. 模块划分清晰:在团队协作开发中,中介者模式有助于清晰地划分各个模块的职责。同事对象专注于自身的业务功能实现,而中介者负责协调各个模块之间的交互。这使得团队成员可以更加明确自己所负责模块的边界和功能,减少模块之间的相互干扰。
  2. 降低沟通成本:由于对象之间的交互通过中介者进行,各个模块之间不需要深入了解其他模块的内部实现细节,只需要通过中介者提供的接口进行交互。这大大降低了团队成员之间的沟通成本,特别是在大型团队中,不同模块由不同的小组负责开发时,这种优势更加明显。
  3. 便于并行开发:中介者模式使得各个同事对象之间的耦合度降低,不同的同事对象可以独立进行开发、测试和部署。团队成员可以并行开发不同的模块,然后通过中介者将这些模块集成起来,提高开发效率。

中介者模式在大型项目中的挑战与应对策略

  1. 中介者复杂性挑战:在大型项目中,随着同事对象数量的增加和交互逻辑的复杂化,中介者可能会变得非常复杂,难以维护和理解。应对策略是对中介者进行合理的拆分和分层设计。可以根据业务功能或者交互类型将中介者拆分成多个子中介者,每个子中介者负责一类特定的交互逻辑。同时,采用分层架构,将不同层次的交互逻辑放在不同层次的中介者中,使得中介者的结构更加清晰。
  2. 性能挑战:在大型项目的高并发场景下,中介者可能成为性能瓶颈。可以采用分布式缓存、负载均衡等技术来优化中介者的性能。例如,将一些常用的交互数据缓存起来,减少中介者的计算量。同时,通过负载均衡将请求均匀分配到多个中介者实例上,提高系统的并发处理能力。
  3. 可扩展性挑战:随着项目的发展,可能需要不断添加新的同事对象或者修改现有同事对象的交互逻辑。为了应对可扩展性挑战,在设计中介者时应该采用接口化和抽象化的设计原则。使得新的同事对象可以方便地接入中介者,并且在修改交互逻辑时对现有系统的影响最小化。

中介者模式在不同行业 Java 项目中的独特应用

  1. 医疗行业:在医疗信息系统中,不同的科室(如挂号科室、检查科室、治疗科室等)之间需要进行信息交互。可以使用中介者模式,创建一个医疗信息中介者来协调各个科室之间的信息传递和业务流程。例如,当患者挂号后,挂号科室通过中介者将患者信息传递给相应的检查科室和治疗科室,各个科室之间不需要直接了解其他科室的信息系统结构和接口,提高了系统的集成性和可维护性。
  2. 金融行业:在金融交易系统中,不同的交易主体(如投资者、券商、银行等)之间存在复杂的交互。中介者模式可以用于管理这些交易主体之间的信息传递和交易流程。例如,投资者的交易指令通过中介者传递给券商和银行,由中介者协调处理交易的各个环节,确保交易的顺利进行,同时降低各个交易主体之间的耦合度,便于系统的扩展和升级。
  3. 制造业:在制造业的生产管理系统中,不同的生产环节(如原材料采购、生产加工、质量检测等)之间需要进行紧密的协作和信息交互。可以利用中介者模式,创建一个生产管理中介者来协调各个生产环节之间的工作。例如,当原材料采购完成后,通过中介者通知生产加工环节开始生产,并且将相关信息传递给质量检测环节做好准备,提高生产流程的协同性和效率。