桥接模式(Bridge)
前言
桥接模式将抽象部分与实现部分分离,使它们可以独立变化。它通过组合代替继承来解决多维度变化的问题,是避免"类爆炸"的利器。本文将详细讲解桥接模式的核心原理及实际应用。
一、核心概念
1.1 定义
将抽象部分与它的实现部分分离,使它们都可以独立地变化。
1.2 核心角色
| 角色 | 说明 |
|---|---|
| 抽象(Abstraction) | 定义抽象接口,持有实现者引用 |
| 扩展抽象(RefinedAbstraction) | 扩展抽象的额外功能 |
| 实现者(Implementor) | 定义实现接口 |
| 具体实现者(ConcreteImplementor) | 实现具体逻辑 |
1.3 解决的问题
如果不使用桥接模式:
Shape (抽象)
├── Circle (具体形状)
│ ├── RedCircle
│ ├── BlueCircle
│ └── GreenCircle
├── Square
│ ├── RedSquare
│ ├── BlueSquare
│ └── GreenSquare
└── Triangle
├── RedTriangle
├── BlueTriangle
└── GreenTriangle
→ 类数量 = 形状数 × 颜色数 = 3 × 3 = 9 个类
使用桥接模式后:
Shape (持有 Color 引用)
├── Circle
├── Square
└── Triangle
Color (实现接口)
├── Red
├── Blue
└── Green
→ 类数量 = 形状数 + 颜色数 = 3 + 3 = 6 个类二、代码实现
2.1 基础实现
php
<?php
// 实现者接口
interface Implementor
{
public function operationImpl(): string;
}
// 具体实现者 A
class ConcreteImplementorA implements Implementor
{
public function operationImpl(): string
{
return "Implementor A";
}
}
// 具体实现者 B
class ConcreteImplementorB implements Implementor
{
public function operationImpl(): string
{
return "Implementor B";
}
}
// 抽象类:持有实现者引用
abstract class Abstraction
{
protected Implementor $implementor;
public function __construct(Implementor $implementor)
{
$this->implementor = $implementor;
}
abstract public function operation(): string;
}
// 扩展抽象
class RefinedAbstraction extends Abstraction
{
public function operation(): string
{
return "RefinedAbstraction: " . $this->implementor->operationImpl();
}
}
// 使用
$implA = new ConcreteImplementorA();
$abstraction = new RefinedAbstraction($implA);
echo $abstraction->operation() . PHP_EOL;
// RefinedAbstraction: Implementor A
$implB = new ConcreteImplementorB();
$abstraction2 = new RefinedAbstraction($implB);
echo $abstraction2->operation() . PHP_EOL;
// RefinedAbstraction: Implementor B2.2 实际案例:形状与颜色
php
<?php
// 颜色实现者接口
interface Color
{
public function fill(): string;
}
// 具体颜色
class Red implements Color
{
public function fill(): string
{
return "Red";
}
}
class Blue implements Color
{
public function fill(): string
{
return "Blue";
}
}
class Green implements Color
{
public function fill(): string
{
return "Green";
}
}
// 形状抽象:持有颜色引用
abstract class Shape
{
protected Color $color;
public function __construct(Color $color)
{
$this->color = $color;
}
abstract public function draw(): string;
}
// 具体形状
class Circle extends Shape
{
public function draw(): string
{
return "Drawing Circle with {$this->color->fill()} color";
}
}
class Square extends Shape
{
public function draw(): string
{
return "Drawing Square with {$this->color->fill()} color";
}
}
class Triangle extends Shape
{
public function draw(): string
{
return "Drawing Triangle with {$this->color->fill()} color";
}
}
// 使用:形状和颜色独立变化
$redCircle = new Circle(new Red());
echo $redCircle->draw() . PHP_EOL; // Drawing Circle with Red color
$blueSquare = new Square(new Blue());
echo $blueSquare->draw() . PHP_EOL; // Drawing Square with Blue color
$greenTriangle = new Triangle(new Green());
echo $greenTriangle->draw() . PHP_EOL; // Drawing Triangle with Green color2.3 实际案例:消息发送器
php
<?php
// 消息发送实现者
interface MessageSender
{
public function send(string $message): void;
}
// 邮件发送
class EmailSender implements MessageSender
{
public function send(string $message): void
{
echo "📧 Email: {$message}" . PHP_EOL;
}
}
// 短信发送
class SmsSender implements MessageSender
{
public function send(string $message): void
{
echo "📱 SMS: {$message}" . PHP_EOL;
}
}
// 推送通知
class PushSender implements MessageSender
{
public function send(string $message): void
{
echo "🔔 Push: {$message}" . PHP_EOL;
}
}
// 消息抽象
abstract class Message
{
protected MessageSender $sender;
public function __construct(MessageSender $sender)
{
$this->sender = $sender;
}
abstract public function deliver(string $content): void;
}
// 普通消息
class TextMessage extends Message
{
public function deliver(string $content): void
{
$this->sender->send("[Text] {$content}");
}
}
// 紧急消息:添加前缀
class UrgentMessage extends Message
{
public function deliver(string $content): void
{
$this->sender->send("[URGENT] {$content}");
}
}
// 使用:消息类型和发送方式独立变化
$email = new EmailSender();
$sms = new SmsSender();
$normalMessage = new TextMessage($email);
$normalMessage->deliver("Hello World");
// 📧 Email: [Text] Hello World
$urgentMessage = new UrgentMessage($sms);
$urgentMessage->deliver("Server Down");
// 📱 SMS: [URGENT] Server Down三、适用场景
| 场景 | 说明 |
|---|---|
| 多维度变化 | 形状×颜色、消息类型×发送方式 |
| 跨平台应用 | 抽象逻辑×平台实现 |
| 避免类爆炸 | 减少继承层级 |
| 运行时切换实现 | 动态替换实现者 |
| 驱动/渲染器 | 接口统一,实现多样 |
四、优缺点分析
| 优点 | 缺点 |
|---|---|
| 解耦抽象和实现 | 代码复杂度增加 |
| 独立扩展两个维度 | 需要维护更多类 |
| 符合开闭原则 | 设计难度增加 |
| 运行时切换实现 | 增加间接层 |
| 避免类爆炸 | 简单场景过度设计 |
五、常见踩坑与问题排查
5.1 与策略模式混淆
php
<?php
// 桥接模式:关注两个维度的独立变化,抽象和实现分离
// Shape × Color → Shape 持有 Color 引用
// 策略模式:关注算法切换,一个维度
// Context 持有 Strategy,运行时切换
// 核心区别:桥接是结构型,策略是行为型
// 桥接的抽象和实现都有层级结构,策略只有一个策略接口5.2 过度抽象
php
<?php
// 问题:简单场景使用桥接模式
class SimpleButton
{
// 只有红色和蓝色两种,不需要桥接
}
// 解决:维度少且固定时,直接继承即可六、优化方案与进阶
6.1 结合抽象工厂
php
<?php
// 用工厂创建实现者
interface DeviceFactory
{
public function createRenderer(): Renderer;
public function createInput(): Input;
}
class WindowsFactory implements DeviceFactory
{
public function createRenderer(): Renderer
{
return new WindowsRenderer();
}
public function createInput(): Input
{
return new WindowsInput();
}
}
// 桥接:抽象使用工厂创建的实现者
abstract class UIAbstraction
{
protected Renderer $renderer;
protected Input $input;
public function __construct(DeviceFactory $factory)
{
$this->renderer = $factory->createRenderer();
$this->input = $factory->createInput();
}
}七、全文总结
桥接模式的核心是 将抽象与实现分离,使两个维度可以独立变化。
核心要点:
- 通过组合代替继承,解决多维度变化问题
- 抽象持有实现者引用,运行时可切换
- 适用于形状×颜色、消息类型×发送方式等场景
- 避免类爆炸,类数量从 M×N 减少为 M+N
- 与策略模式相似,但桥接关注结构维度,策略关注行为切换
