Skip to content

桥接模式(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 B

2.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 color

2.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();
    }
}

七、全文总结

桥接模式的核心是 将抽象与实现分离,使两个维度可以独立变化

核心要点

  1. 通过组合代替继承,解决多维度变化问题
  2. 抽象持有实现者引用,运行时可切换
  3. 适用于形状×颜色、消息类型×发送方式等场景
  4. 避免类爆炸,类数量从 M×N 减少为 M+N
  5. 与策略模式相似,但桥接关注结构维度,策略关注行为切换