程序员必知!中介者模式的实战应用与案例分析

中介者模式通过引入中介类降低对象间耦合度,在电商平台中,卖家、买家、物流公司和支付平台原本需复杂交互,在引入"交易中介"类后,各角色只需与中介交互,由中介协调各方操作,从而简化了交互流程,降低了类间依赖,使系统更灵活可维护。

定义

中介者模式主要用于减少类之间的耦合,它用一个中介类来封装一系列对象间的交互,使这些对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

举一个业务中的例子来说明,假设有一个电商平台,其中有卖家、买家、物流公司和支付平台四个角色,在没有中介者的情况下,这四个角色之间可能需要进行复杂的交互,比如卖家要直接联系物流公司发货,买家要直接联系支付平台进行支付等,这样的设计会导致类之间的耦合度很高,一旦某个角色发生变化,可能会影响到其他角色。

而引入中介者模式后,可以设计一个电商平台的"交易中介"类,这个类中介了卖家、买家、物流公司和支付平台之间的所有交互,卖家只需要将商品信息和买家信息提交给交易中介,交易中介会负责联系物流公司进行发货,并通知买家进行支付,买家支付完成后,交易中介会通知卖家和物流公司更新订单状态,这样,卖家、买家、物流公司和支付平台之间的耦合度就大大降低了,每个角色只需要和交易中介进行交互,而不需要直接和其他角色进行交互。

在这个场景中中,交易中介类就起到了中介者的作用,它将一系列对象间的交互封装起来,使这些对象之间的耦合度降低,提高了系统的灵活性和可维护性。

代码案例

反例

下面是一个未使用中介者模式的反例代码,假如,有一个聊天应用的简单模型,其中包括User(用户)和GroupChat(群聊)类,每个User对象都直接与其他User对象通信,如下代码演示:

java 复制代码
public class User {  
    private String name;  
      
    public User(String name) {  
        this.name = name;  
    }  
      
    public String getName() {  
        return name;  
    }  
      
    public void sendMessage(User receiver, String message) {  
        System.out.println(name + " sends a message to " + receiver.getName() + ": " + message);  
    }  
}  
  
public class GroupChat {  
    private List<User> users = new ArrayList<>();  
      
    public void addUser(User user) {  
        users.add(user);  
    }  
      
    public void notifyAllUsers(String message) {  
        for (User user : users) {  
            for (User otherUser : users) {  
                if (!user.equals(otherUser)) {  
                    user.sendMessage(otherUser, message);
                }  
            }  
        }  
    }  
}  
  
public class Client {  
    public static void main(String[] args) {  
        User alice = new User("Alice");  
        User bob = new User("Bob");  
        User charlie = new User("Charlie");  
          
        GroupChat chat = new GroupChat();  
        chat.addUser(alice);  
        chat.addUser(bob);  
        chat.addUser(charlie);  
          

        alice.sendMessage(bob, "Hi Bob, how are you?"); 
        alice.sendMessage(charlie, "Hi Charlie, what's up?"); 
          
        chat.notifyAllUsers("Everyone, there will be a maintenance tonight.");  
    }  
}

输出结果,如下:

java 复制代码
Alice sends a message to Bob: Hi Bob, how are you?  
Alice sends a message to Charlie: Hi Charlie, what's up?  
Alice sends a message to Bob: Everyone, there will be a maintenance tonight.  
Alice sends a message to Charlie: Everyone, there will be a maintenance tonight.  
Bob sends a message to Alice: Everyone, there will be a maintenance tonight.  
Bob sends a message to Charlie: Everyone, there will be a maintenance tonight.  
Charlie sends a message to Alice: Everyone, there will be a maintenance tonight.  
Charlie sends a message to Bob: Everyone, there will be a maintenance tonight.

在这个反例中,User类直接持有对其他User对象的引用,并直接调用其方法,这导致了类之间的紧密耦合,因为User类需要知道如何与其他User对象通信,此外,GroupChat类虽然被设计出来,但并没有起到中介消息的作用,实际上,当notifyAllUsers方法被调用时,每个用户都会向其他每个用户发送消息,导致了重复的消息和不必要的复杂性。

正例

下面是一个使用中介者模式的正例代码,在这个例子中,有一个聊天应用的模型,包括User(用户)和ChatMediator(聊天中介)类,ChatMediator类作为中介者,封装了用户之间的通信逻辑,使得用户之间不需要直接相互引用,如下代码:

java 复制代码
import java.util.*;  
  
// User.java  
public class User {  
    private String name;  
    private ChatMediator chatMediator;  
      
    public User(String name, ChatMediator chatMediator) {  
        this.name = name;  
        this.chatMediator = chatMediator;  
    }  
      
    public String getName() {  
        return name;  
    }  
      
    // 用户通过中介者发送消息  
    public void sendMessage(String receiverName, String message) {  
        chatMediator.relayMessage(this, receiverName, message);  
    }  
}  
  
// ChatMediator.java  
public class ChatMediator {  
    private Map<String, User> users = new HashMap<>();  
      
    public void registerUser(User user) {  
        users.put(user.getName(), user);  
    }  
      
    // 中介者负责将消息传递给指定的接收者  
    public void relayMessage(User sender, String receiverName, String message) {  
        User receiver = users.get(receiverName);  
        if (receiver != null) {  
            System.out.println(sender.getName() + " sends a message to " + receiver.getName() + ": " + message);  
            // 这里可以添加额外的逻辑,比如记录消息、通知其他服务等  
        } else {  
            System.out.println("Receiver " + receiverName + " is not online.");  
        }  
    }  
}  
  
// 客户端代码  
public class Client {  
    public static void main(String[] args) {  
        // 创建中介者和用户  
        ChatMediator chatMediator = new ChatMediator();  
        User alice = new User("Alice", chatMediator);  
        User bob = new User("Bob", chatMediator);  
          
        // 用户注册到中介者  
        chatMediator.registerUser(alice);  
        chatMediator.registerUser(bob);  
          
        // Alice通过中介者发送消息给Bob  
        alice.sendMessage("Bob", "Hi Bob, how are you?");  
          
        // Bob通过中介者回复消息给Alice  
        bob.sendMessage("Alice", "I'm good, thanks!");  
          
        // 尝试发送消息给一个未注册的用户  
        alice.sendMessage("Charlie", "Hey Charlie, are you there?");  
    }  
}

输出结果:

java 复制代码
Alice sends a message to Bob: Hi Bob, how are you?  
Bob sends a message to Alice: I'm good, thanks!  
Receiver Charlie is not online.

在这个正例中,User类不直接持有对其他User对象的引用,而是通过ChatMediator中介者来发送消息,ChatMediator维护了一个用户列表,并负责将消息从发送者传递给接收者,这样,User类之间的耦合度降低了,因为用户不需要知道如何与其他用户直接通信,他们只需要与中介者交互。此外,如果未来需要改变通信方式或添加额外的通信逻辑,只需要修改ChatMediator类即可,而不影响User类。

核心总结

中介者模式总结

通过引入中介者,使得各个组件之间不再直接相互依赖,减少了系统的复杂性,他将原本分散的交互逻辑集中管理,使得这些逻辑更加清晰和易于维护,由于组件间的通信都通过中介者进行,因此添加新组件或修改现有组件的交互方式变得更加容易。但随着系统的扩展,它可能需要处理越来越多的交互逻辑,导致其代码变得庞大且难以维护,为了实现中介者模式,有时可能需要创建额外的抽象类和接口,这可能会增加系统的复杂性和理解难度。

在确实需要降低组件间耦合度的情况下使用中介者模式,避免过度设计,可以考虑与其他设计模式(如观察者模式)结合使用,以实现更灵活和强大的功能。

和其它模式对比

中介者模式和装饰者模式两者的区别:

中介者模式主要用于降低多个对象之间的耦合度,通过引入一个中介者对象,其它所有相关对象都通过该中介者对象进行通信,而不是直接相互引用,当中介者模式中的某一个对象发生改变时,只需要通知中介者对象,由中介者对象负责与其他对象的交互,这样可以简化对象之间的交互,降低系统的复杂性。

装饰者模式则侧重于在不改变对象自身的基础上,动态地给对象添加新的功能或方法,装饰者模式通过创建一个装饰类,将原始类作为成员变量进行包装,并在装饰类中提供与原始类相同的方法,这些方法可以在调用原始类方法之前或之后执行一些额外的操作,这样可以实现对原始类功能的动态扩展,而无需修改原始类的代码。

总结,中介者模式主要用于解决对象之间的紧耦合问题,通过引入中介者来协调对象之间的交互;而装饰者模式则主要用于在不改变原始类的基础上,动态地给对象添加新的功能或方法。

相关推荐
码农派大星。8 分钟前
Spring Boot 配置文件
java·spring boot·后端
杜杜的man1 小时前
【go从零单排】go中的结构体struct和method
开发语言·后端·golang
幼儿园老大*1 小时前
走进 Go 语言基础语法
开发语言·后端·学习·golang·go
llllinuuu1 小时前
Go语言结构体、方法与接口
开发语言·后端·golang
cookies_s_s1 小时前
Golang--协程和管道
开发语言·后端·golang
为什么这亚子1 小时前
九、Go语言快速入门之map
运维·开发语言·后端·算法·云原生·golang·云计算
想进大厂的小王1 小时前
项目架构介绍以及Spring cloud、redis、mq 等组件的基本认识
redis·分布式·后端·spring cloud·微服务·架构
customer082 小时前
【开源免费】基于SpringBoot+Vue.JS医院管理系统(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·开源·intellij-idea
2402_857589362 小时前
SpringBoot框架:作业管理技术新解
java·spring boot·后端
一只爱打拳的程序猿2 小时前
【Spring】更加简单的将对象存入Spring中并使用
java·后端·spring