模式定义

中介者模式是一种行为型设计模式,它用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式将多对多的复杂交互关系转化为一对多的关系,简化了对象之间的通信。

模式结构

graph TD A[Mediator] --> B[Colleague] B --> C[ConcreteColleague1] B --> D[ConcreteColleague2] C --> A D --> A

实现方式

基础实现

定义中介者接口和同事类抽象类,实现具体中介者和具体同事类。

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

// 同事类抽象类
abstract class User {
    protected ChatMediator mediator;
    protected String name;
    
    public User(ChatMediator med, String name) {
        this.mediator = med;
        this.name = name;
    }
    
    public abstract void send(String msg);
    public abstract void receive(String msg);
}

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

// 具体同事类
class UserImpl extends User {
    public UserImpl(ChatMediator med, String name) {
        super(med, name);
    }
    
    @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);
    }
}

使用示例

public class MediatorPatternDemo {
    public static void main(String[] args) {
        ChatMediator mediator = new ChatMediatorImpl();
        
        User user1 = new UserImpl(mediator, "张三");
        User user2 = new UserImpl(mediator, "李四");
        User user3 = new UserImpl(mediator, "王五");
        User user4 = new UserImpl(mediator, "赵六");
        
        mediator.addUser(user1);
        mediator.addUser(user2);
        mediator.addUser(user3);
        mediator.addUser(user4);
        
        user1.send("大家好!");
        System.out.println();
        user2.send("你好,张三!");
    }
}

经典案例

1. Java Timer类

Java中的Timer类是中介者模式的一个应用:

// Timer作为中介者协调多个TimerTask对象
public class TimerMediatorExample {
    public static void main(String[] args) {
        Timer timer = new Timer();
        
        // 创建任务
        TimerTask task1 = new TimerTask() {
            @Override
            public void run() {
                System.out.println("任务1执行: " + new Date());
            }
        };
        
        TimerTask task2 = new TimerTask() {
            @Override
            public void run() {
                System.out.println("任务2执行: " + new Date());
            }
        };
        
        // Timer作为中介者调度任务
        timer.scheduleAtFixedRate(task1, 0, 2000); // 每2秒执行一次
        timer.scheduleAtFixedRate(task2, 1000, 3000); // 每3秒执行一次,延迟1秒开始
        
        // 运行5秒后取消所有任务
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        timer.cancel();
    }
}

2. MVC框架中的控制器

MVC架构中的控制器(Controller)扮演了中介者的角色:

// 中介者接口
interface UIControlMediator {
    void notify(UIComponent component, String event);
}

// 同事类抽象类
abstract class UIComponent {
    protected UIControlMediator mediator;
    
    public UIComponent(UIControlMediator mediator) {
        this.mediator = mediator;
    }
}

// 具体同事类 - 文本框
class TextBox extends UIComponent {
    private String text = "";
    
    public TextBox(UIControlMediator mediator) {
        super(mediator);
    }
    
    public void setText(String text) {
        this.text = text;
        // 通知中介者
        mediator.notify(this, "textChanged");
    }
    
    public String getText() {
        return text;
    }
}

// 具体同事类 - 按钮
class Button extends UIComponent {
    private String label;
    private boolean enabled = true;
    
    public Button(UIControlMediator mediator, String label) {
        super(mediator);
        this.label = label;
    }
    
    public void click() {
        if (enabled) {
            System.out.println("按钮 '" + label + "' 被点击");
            mediator.notify(this, "clicked");
        }
    }
    
    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }
}

// 具体同事类 - 标签
class Label extends UIComponent {
    private String text = "";
    
    public Label(UIControlMediator mediator) {
        super(mediator);
    }
    
    public void setText(String text) {
        this.text = text;
        System.out.println("标签更新为: " + text);
    }
    
    public String getText() {
        return text;
    }
}

// 具体中介者
class DialogMediator implements UIControlMediator {
    private TextBox usernameTextBox;
    private TextBox passwordTextBox;
    private Button loginButton;
    private Button resetButton;
    private Label statusLabel;
    
    public DialogMediator(TextBox username, TextBox password, 
                         Button login, Button reset, Label status) {
        this.usernameTextBox = username;
        this.passwordTextBox = password;
        this.loginButton = login;
        this.resetButton = reset;
        this.statusLabel = status;
    }
    
    @Override
    public void notify(UIComponent component, String event) {
        if (component == usernameTextBox && "textChanged".equals(event)) {
            checkLoginEnable();
        } else if (component == passwordTextBox && "textChanged".equals(event)) {
            checkLoginEnable();
        } else if (component == loginButton && "clicked".equals(event)) {
            performLogin();
        } else if (component == resetButton && "clicked".equals(event)) {
            resetForm();
        }
    }
    
    private void checkLoginEnable() {
        String username = usernameTextBox.getText();
        String password = passwordTextBox.getText();
        loginButton.setEnabled(username.length() > 0 && password.length() > 0);
    }
    
    private void performLogin() {
        String username = usernameTextBox.getText();
        String password = passwordTextBox.getText();
        statusLabel.setText("正在登录 " + username + "...");
        // 模拟登录过程
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        statusLabel.setText("登录成功!");
    }
    
    private void resetForm() {
        usernameTextBox.setText("");
        passwordTextBox.setText("");
        statusLabel.setText("表单已重置");
    }
}

// 使用示例
public class MVCMediatorDemo {
    public static void main(String[] args) {
        // 创建UI组件
        TextBox usernameTextBox = new TextBox(null);
        TextBox passwordTextBox = new TextBox(null);
        Button loginButton = new Button(null, "登录");
        Button resetButton = new Button(null, "重置");
        Label statusLabel = new Label(null);
        
        // 创建中介者
        DialogMediator mediator = new DialogMediator(
            usernameTextBox, passwordTextBox, 
            loginButton, resetButton, statusLabel);
        
        // 设置组件的中介者
        usernameTextBox = new TextBox(mediator);
        passwordTextBox = new TextBox(mediator);
        loginButton = new Button(mediator, "登录");
        resetButton = new Button(mediator, "重置");
        statusLabel = new Label(mediator);
        
        // 模拟用户交互
        System.out.println("=== 用户开始输入 ===");
        usernameTextBox.setText("admin");
        passwordTextBox.setText("123456");
        
        System.out.println("\n=== 用户点击登录 ===");
        loginButton.click();
        
        System.out.println("\n=== 用户点击重置 ===");
        resetButton.click();
    }
}

应用场景

优缺点

优点

  • 降低复杂性:将一对多转换为一对一,降低系统复杂性
  • 减少子类生成:避免了大量子类的生成,简化了对象之间的交互
  • 降低类间耦合:各个同事类之间解耦,它们只与中介者通信
  • 符合迪米特法则:各个同事类之间解耦,符合最少知道原则

缺点

  • 中介者类复杂:中介者类可能变得非常复杂,难以维护
  • 系统性能受影响:中介者类可能成为系统性能的瓶颈
  • 不符合开闭原则:增加新的同事类时可能需要修改中介者类