中介者模式:解耦对象交互的协调艺术

2025/10/16 Design Patterns 共 6826 字,约 20 分钟

中介者模式:对象交互的协调者

在软件开发中,我们经常会遇到多个对象之间相互通信的场景。当对象间的交互关系变得复杂时,系统往往会面临耦合度高、可维护性差的问题。中介者模式正是为了解决这类问题而生的行为型设计模式。

什么是中介者模式?

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

核心思想

中介者模式的核心思想是:将对象间的复杂交互关系转移到中介者对象中。原本需要相互通信的对象现在只需要与中介者通信,由中介者来协调各个对象的行为。

为什么需要中介者模式?

问题场景

想象一个聊天室系统的设计,在没有中介者模式的情况下,每个用户对象都需要维护对其他所有用户对象的引用:

// 问题代码:紧耦合的聊天室实现
class User {
    private String name;
    private List<User> users;
    
    public User(String name, List<User> users) {
        this.name = name;
        this.users = users;
    }
    
    public void sendMessage(String message) {
        for (User user : users) {
            if (user != this) {
                user.receiveMessage(this.name + ": " + message);
            }
        }
    }
    
    public void receiveMessage(String message) {
        System.out.println(name + " 收到消息: " + message);
    }
}

这种设计的缺点很明显:

  • 耦合度高:每个用户都需要知道其他所有用户
  • 难以维护:添加或删除用户需要修改所有相关对象
  • 扩展性差:新增功能(如消息过滤、权限控制)需要在每个用户中实现

解决方案

引入中介者模式后,系统结构变得更加清晰:

// 中介者接口
interface ChatMediator {
    void sendMessage(String message, User user);
    void addUser(User user);
}

// 具体中介者
class ChatRoom implements ChatMediator {
    private List<User> users;
    
    public ChatRoom() {
        this.users = new ArrayList<>();
    }
    
    @Override
    public void addUser(User user) {
        this.users.add(user);
    }
    
    @Override
    public void sendMessage(String message, User sender) {
        for (User user : users) {
            // 不向发送者自己发送消息
            if (user != sender) {
                user.receiveMessage(message);
            }
        }
    }
}

// 用户类
abstract class User {
    protected ChatMediator mediator;
    protected String name;
    
    public User(ChatMediator mediator, String name) {
        this.mediator = mediator;
        this.name = name;
    }
    
    public abstract void send(String message);
    public abstract void receiveMessage(String message);
}

// 具体用户类
class ChatUser extends User {
    public ChatUser(ChatMediator mediator, String name) {
        super(mediator, name);
    }
    
    @Override
    public void send(String message) {
        System.out.println(this.name + " 发送消息: " + message);
        mediator.sendMessage(this.name + ": " + message, this);
    }
    
    @Override
    public void receiveMessage(String message) {
        System.out.println(this.name + " 收到消息: " + message);
    }
}

中介者模式的结构

中介者模式包含以下几个核心角色:

1. Mediator(中介者接口)

定义各个同事对象交互的接口

2. ConcreteMediator(具体中介者)

实现中介者接口,协调各个同事对象的行为

3. Colleague(同事类)

每个同事对象都知道它的中介者对象,通过中介者与其他同事对象通信

实际应用示例

案例一:飞机塔台调度系统

在航空领域,塔台作为中介者协调所有飞机的起降:

// 塔台中介者
interface ControlTower {
    void requestLanding(Aircraft aircraft);
    void notifyTakeoff(Aircraft aircraft);
    boolean isRunwayAvailable();
}

class AirportControlTower implements ControlTower {
    private boolean runwayAvailable = true;
    private Queue<Aircraft> landingQueue = new LinkedList<>();
    
    @Override
    public void requestLanding(Aircraft aircraft) {
        if (runwayAvailable) {
            runwayAvailable = false;
            System.out.println("塔台: " + aircraft.getName() + " 可以降落");
            aircraft.performLanding();
        } else {
            landingQueue.add(aircraft);
            System.out.println("塔台: " + aircraft.getName() + " 请等待降落");
        }
    }
    
    @Override
    public void notifyTakeoff(Aircraft aircraft) {
        runwayAvailable = true;
        System.out.println("塔台: " + aircraft.getName() + " 已起飞");
        if (!landingQueue.isEmpty()) {
            Aircraft nextAircraft = landingQueue.poll();
            requestLanding(nextAircraft);
        }
    }
    
    @Override
    public boolean isRunwayAvailable() {
        return runwayAvailable;
    }
}

// 飞机类
abstract class Aircraft {
    protected ControlTower controlTower;
    protected String name;
    
    public Aircraft(ControlTower controlTower, String name) {
        this.controlTower = controlTower;
        this.name = name;
    }
    
    public String getName() {
        return name;
    }
    
    public abstract void requestLanding();
    public abstract void performLanding();
    public abstract void takeoff();
}

class CommercialAircraft extends Aircraft {
    public CommercialAircraft(ControlTower controlTower, String name) {
        super(controlTower, name);
    }
    
    @Override
    public void requestLanding() {
        System.out.println(name + " 请求降落");
        controlTower.requestLanding(this);
    }
    
    @Override
    public void performLanding() {
        System.out.println(name + " 正在降落...");
        // 模拟降落过程
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name + " 降落完成");
        takeoff(); // 简化逻辑:降落后立即起飞
    }
    
    @Override
    public void takeoff() {
        System.out.println(name + " 请求起飞");
        // 模拟起飞准备
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name + " 已起飞");
        controlTower.notifyTakeoff(this);
    }
}

// 使用示例
public class AirportDemo {
    public static void main(String[] args) {
        ControlTower tower = new AirportControlTower();
        
        Aircraft flight1 = new CommercialAircraft(tower, "CA123");
        Aircraft flight2 = new CommercialAircraft(tower, "UA456");
        Aircraft flight3 = new CommercialAircraft(tower, "DL789");
        
        flight1.requestLanding();
        flight2.requestLanding();
        flight3.requestLanding();
    }
}

案例二:GUI组件交互

在图形用户界面中,各种组件(按钮、文本框、复选框等)通过中介者进行协调:

// 对话框中介者
interface DialogMediator {
    void widgetChanged(Widget widget);
}

class LoginDialog implements DialogMediator {
    private Button loginButton;
    private TextBox usernameTextBox;
    private TextBox passwordTextBox;
    private CheckBox rememberMeCheckBox;
    
    public void setLoginButton(Button button) {
        this.loginButton = button;
    }
    
    public void setUsernameTextBox(TextBox textBox) {
        this.usernameTextBox = textBox;
    }
    
    public void setPasswordTextBox(TextBox textBox) {
        this.passwordTextBox = textBox;
    }
    
    public void setRememberMeCheckBox(CheckBox checkBox) {
        this.rememberMeCheckBox = checkBox;
    }
    
    @Override
    public void widgetChanged(Widget widget) {
        if (widget == usernameTextBox || widget == passwordTextBox) {
            validateForm();
        } else if (widget == loginButton) {
            performLogin();
        }
    }
    
    private void validateForm() {
        boolean isValid = !usernameTextBox.getText().isEmpty() 
                        && !passwordTextBox.getText().isEmpty();
        loginButton.setEnabled(isValid);
    }
    
    private void performLogin() {
        String username = usernameTextBox.getText();
        String password = passwordTextBox.getText();
        boolean rememberMe = rememberMeCheckBox.isChecked();
        
        System.out.println("执行登录: 用户名=" + username + 
                         ", 记住我=" + rememberMe);
        // 实际的登录逻辑...
    }
}

// 基础组件类
abstract class Widget {
    protected DialogMediator mediator;
    
    public Widget(DialogMediator mediator) {
        this.mediator = mediator;
    }
    
    public void changed() {
        mediator.widgetChanged(this);
    }
}

// 具体组件
class Button extends Widget {
    private boolean enabled = true;
    
    public Button(DialogMediator mediator) {
        super(mediator);
    }
    
    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
        System.out.println("按钮 " + (enabled ? "启用" : "禁用"));
    }
    
    public void click() {
        if (enabled) {
            System.out.println("按钮被点击");
            changed();
        }
    }
}

class TextBox extends Widget {
    private String text = "";
    
    public TextBox(DialogMediator mediator) {
        super(mediator);
    }
    
    public void setText(String text) {
        this.text = text;
        System.out.println("文本框内容: " + text);
        changed();
    }
    
    public String getText() {
        return text;
    }
}

class CheckBox extends Widget {
    private boolean checked = false;
    
    public CheckBox(DialogMediator mediator) {
        super(mediator);
    }
    
    public void setChecked(boolean checked) {
        this.checked = checked;
        System.out.println("复选框 " + (checked ? "选中" : "未选中"));
        changed();
    }
    
    public boolean isChecked() {
        return checked;
    }
}

中介者模式的优缺点

优点

  1. 降低耦合度:将对象间的一对多关系转变为一对一关系
  2. 集中控制:将交互逻辑集中在中介者中,便于理解和维护
  3. 易于扩展:新增同事类只需修改中介者,不影响其他同事类
  4. 复用性提高:中介者逻辑可以独立复用

缺点

  1. 中介者可能变得复杂:如果交互关系过于复杂,中介者类可能变得庞大难以维护
  2. 性能考虑:所有通信都通过中介者,可能成为性能瓶颈

适用场景

中介者模式适用于以下场景:

  • 对象间存在复杂的引用关系,系统结构混乱难以理解
  • 一个对象引用很多其他对象,直接通信导致复用困难
  • 想通过一个中间类封装多个类中的行为,又不想生成太多子类
  • 系统中对象间的交互虽有定义但行为复杂,想自定义分布在多个类中的行为

最佳实践

  1. 合理设计中介者接口:确保接口足够通用,能够适应未来的扩展需求
  2. 避免上帝对象:不要让中介者承担过多职责,必要时可以引入多个中介者
  3. 考虑性能优化:对于高频交互场景,可以考虑异步处理或缓存机制
  4. 测试策略:中介者模式使得单元测试更加容易,可以单独测试各个同事类

总结

中介者模式通过引入一个协调者来管理对象间的复杂交互,有效地降低了系统的耦合度。虽然它可能导致中介者类变得复杂,但在处理多个对象间复杂交互的场景下,中介者模式提供了清晰的解决方案。

在实际项目中,我们应该根据具体需求权衡是否使用中介者模式。当对象间的交互逻辑相对稳定且不会频繁变化时,中介者模式能够显著提升代码的可维护性和可扩展性。

通过本文的讲解和代码示例,相信你已经对中介者模式有了深入的理解。在合适的场景下应用这一模式,将帮助你构建更加清晰、可维护的软件系统。

文档信息

Search

    Table of Contents