文章

设计模式实战:深入理解中介者模式

模式定义

中介者模式(Mediator Pattern)是行为型设计模式,通过中介对象封装一系列对象交互,使各对象不需要显式相互引用,从而降低耦合度。该模式如同交通指挥中心,协调多方交互关系。

核心思想

  1. 交互中心化:所有通信通过中介者进行

  2. 对象解耦:消除对象间的网状依赖

  3. 统一控制:集中管理交互规则

  4. 简化协议:定义清晰的通信接口

适用场景

  • 对象间存在复杂网状引用关系

  • 需要集中管理多方交互规则

  • 跨系统通信需要中间协调

  • 交互协议需要统一维护

模式结构

  • Mediator:中介者接口,定义通信方法

  • ConcreteMediator:具体中介实现,协调各对象

  • Colleague:交互对象基类

  • ConcreteColleague:具体交互对象


PHP实现示例:聊天室消息中介

<?php
// 中介者接口
interface ChatMediator {
    public function sendMessage(string $msg, User $user);
    public function addUser(User $user);
}

// 具体中介者:聊天室服务器
class ChatRoom implements ChatMediator {
    private $users = [];

    public function addUser(User $user) {
        $this->users[$user->getName()] = $user;
    }

    public function sendMessage(string $msg, User $sender) {
        foreach ($this->users as $name => $user) {
            if ($user !== $sender) {
                $user->receive($msg, $sender->getName());
            }
        }
    }
}

// 用户基类
abstract class User {
    protected $mediator;
    protected $name;

    public function __construct(ChatMediator $mediator, string $name) {
        $this->mediator = $mediator;
        $this->name = $name;
        $mediator->addUser($this);
    }

    public function getName(): string {
        return $this->name;
    }

    abstract public function send(string $msg);
    abstract public function receive(string $msg, string $sender);
}

// 具体用户类型
class ChatUser extends User {
    public function send(string $msg) {
        echo "{$this->name} 发送消息: $msg\n";
        $this->mediator->sendMessage($msg, $this);
    }

    public function receive(string $msg, string $sender) {
        echo "{$this->name} 收到来自 {$sender} 的消息: $msg\n";
    }
}

// 客户端使用
$chatRoom = new ChatRoom();

$user1 = new ChatUser($chatRoom, "Alice");
$user2 = new ChatUser($chatRoom, "Bob");
$user3 = new ChatUser($chatRoom, "Charlie");

$user1->send("大家中午吃什么?");
$user2->send("我打算吃披萨");

/* 输出:
Alice 发送消息: 大家中午吃什么?
Bob 收到来自 Alice 的消息: 大家中午吃什么?
Charlie 收到来自 Alice 的消息: 大家中午吃什么?
Bob 发送消息: 我打算吃披萨
Alice 收到来自 Bob 的消息: 我打算吃披萨
Charlie 收到来自 Bob 的消息: 我打算吃披萨
*/

Go实现示例:空中交通管制系统

package main

import (
	"fmt"
	"sync"
)

// 中介者接口
type AirTrafficControl interface {
	RequestLanding(airplane *Airplane) bool
	NotifyTakeoff(airplane *Airplane)
}

// 具体中介者:塔台
type ControlTower struct {
	runwayInUse bool
	waitQueue   []*Airplane
	mu          sync.Mutex
}

func (t *ControlTower) RequestLanding(airplane *Airplane) bool {
	t.mu.Lock()
	defer t.mu.Unlock()

	if !t.runwayInUse {
		t.runwayInUse = true
		fmt.Printf("塔台: %s 允许降落\n", airplane.Name)
		return true
	}

	fmt.Printf("塔台: %s 请等待\n", airplane.Name)
	t.waitQueue = append(t.waitQueue, airplane)
	return false
}

func (t *ControlTower) NotifyTakeoff(airplane *Airplane) {
	t.mu.Lock()
	defer t.mu.Unlock()

	fmt.Printf("塔台: %s 已起飞\n", airplane.Name)
	t.runwayInUse = false

	if len(t.waitQueue) > 0 {
		next := t.waitQueue[0]
		t.waitQueue = t.waitQueue[1:]
		fmt.Printf("塔台: 通知 %s 可以降落\n", next.Name)
		next.ReceiveLandingPermission()
	}
}

// 交互对象:飞机
type Airplane struct {
	Name     string
	mediator AirTrafficControl
}

func (a *Airplane) RequestLanding() {
	if a.mediator.RequestLanding(a) {
		fmt.Printf("%s 开始降落\n", a.Name)
	}
}

func (a *Airplane) ReceiveLandingPermission() {
	fmt.Printf("%s 收到降落许可\n", a.Name)
	a.RequestLanding()
}

func (a *Airplane) Takeoff() {
	fmt.Printf("%s 请求起飞\n", a.Name)
	a.mediator.NotifyTakeoff(a)
}

func main() {
	tower := &ControlTower{}

	planes := []*Airplane{
		{Name: "CA123", mediator: tower},
		{Name: "UA456", mediator: tower},
		{Name: "AA789", mediator: tower},
	}

	var wg sync.WaitGroup
	wg.Add(3)

	// 模拟飞机依次请求降落
	go func() {
		defer wg.Done()
		planes[0].RequestLanding()
		planes[0].Takeoff()
	}()

	go func() {
		defer wg.Done()
		planes[1].RequestLanding()
	}()

	go func() {
		defer wg.Done()
		planes[2].RequestLanding()
	}()

	wg.Wait()
}

/* 输出示例:
塔台: CA123 允许降落
CA123 开始降落
CA123 请求起飞
塔台: CA123 已起飞
塔台: 通知 UA456 可以降落
UA456 收到降落许可
塔台: UA456 允许降落
UA456 开始降落
塔台: UA456 请等待
塔台: AA789 请等待
*/

模式优缺点

优点

  • 减少对象间耦合

  • 集中控制交互逻辑

  • 简化对象协议

  • 提升系统可维护性

缺点

  • 中介者可能成为上帝对象

  • 增加系统复杂度

  • 通信效率可能降低

  • 中介者修改影响全局


不同语言实现差异

特性

PHP

Go

线程安全

单线程无需处理

需使用mutex保证并发安全

接口定义

显式interface声明

隐式接口实现

对象关系

类继承体系

结构体组合

典型应用

GUI组件交互

微服务协调


中介者模式VS其他模式

对比模式

关键区别

观察者

关注状态通知 vs 关注交互协调

外观

封装子系统 vs 协调同级对象

代理

控制单个对象访问 vs 协调多个对象


模式演进方向

  1. 分布式中介者
    结合消息中间件实现跨进程协调

  2. 智能路由
    添加AI算法优化交互决策

  3. 状态管理
    引入状态模式管理中介者行为

  4. 服务网格
    构建基于中介模式的Service Mesh

  5. 容错机制
    实现中介者故障转移和冗余备份


最佳实践建议

  1. 职责明确
    严格限定中介者的协调边界

  2. 协议简化
    定义清晰简洁的通信接口

  3. 性能优化
    对高频交互进行批处理优化

  4. 日志追踪
    添加完整的交互日志记录

  5. 异常隔离
    防止单个组件故障影响全局


总结

中介者模式通过引入协调中心,将复杂的网状交互转化为星型结构,有效降低系统耦合度。该模式在以下场景表现卓越:

  • 多对象存在复杂交互关系

  • 需要集中管理交互规则

  • 系统需要统一通信协议

  • 组件需要动态协调机制

PHP与Go的实现差异体现了不同语言的特性优势:

  • PHP通过类继承体系直观展现对象关系

  • Go利用并发原语实现高性能协调

实际应用中需注意:

  • 避免中介者过度复杂化

  • 合理划分协调边界

  • 注意并发环境下的线程安全

  • 结合具体场景选择同步/异步通信

掌握中介者模式的关键在于理解"中心化协调"的设计哲学,这种通过中间层简化复杂交互的思想,是构建大型分布式系统的重要基础。

License:  CC BY 4.0