桥接模式(Bridge Pattern)是一种结构型设计模式,它的核心是将抽象部分与实现部分分离,使它们可以独立变化。通过引入一个 “桥接” 接口,将两个维度的变化解耦,避免因多维度扩展导致的类爆炸问题。

简单来说,桥接模式就像 “遥控器与电器” 的关系 —— 遥控器(抽象部分)和电器(实现部分)可以独立变化:遥控器可以是红外、蓝牙等类型,电器可以是电视、空调等类型,通过桥接(遥控信号)关联,彼此不直接依赖。

image.png

在上图中:

  • 抽象部分(Abstraction):定义抽象接口,包含一个对实现部分的引用,声明业务方法。
  • 扩展抽象部分(RefinedAbstraction):继承抽象部分,对抽象接口进行扩展和完善。
  • 实现部分接口(Implementor):定义实现部分的接口,与抽象部分的接口对应,但侧重点不同(抽象侧重业务,实现侧重具体操作)。
  • 具体实现(ConcreteImplementorA/B):实现实现部分接口,提供具体的功能实现。
  • 桥接关系:抽象部分通过持有实现部分的引用,将抽象的业务方法委托给实现部分的具体方法,形成 “桥接”。

桥接模式的核心价值是解耦多维度变化,当系统存在两个独立变化的维度(如 “形状与颜色”、”操作系统与软件”)时,使用桥接模式可以避免为每个组合创建单独的类,减少类的数量并提高扩展性。

桥接模式特别适合处理存在两个独立变化维度的场景。
下面以 “消息通知系统” 为例说明其工作原理:消息有不同的类型(如普通消息、紧急消息),同时需要通过不同渠道发送(如短信、邮件、APP 推送)。这两个维度可以独立变化,使用桥接模式能避免类爆炸(如SmsNormalMessageEmailUrgentMessage等大量组合类)。

首先我们定义一个消息发送接口,它只有一个send方法负责发送消息。

1
2
3
4
// 实现部分接口:定义消息发送渠道的接口(第二个变化维度)
interface MessageSender {
void send(String message); // 发送消息的具体实现
}

然后针对不同的消息发送方式,比如短信和Email定义具体的发送消息类

1
2
3
4
5
6
7
// 具体实现1:短信发送
class SmsSender implements MessageSender {
@Override
public void send(String message) {
System.out.println("【短信】发送消息:" + message);
}
}
1
2
3
4
5
6
7
// 具体实现2:邮件发送
class EmailSender implements MessageSender {
@Override
public void send(String message) {
System.out.println("【邮件】发送消息:" + message);
}
}

发送消息的方式不同,我们用上面的代码进行了抽象解耦。同时,消息本身的类型也是不同的。那么我们在对消息进行抽象和实现的解耦。

首先定义消息抽象,我们让每个消息都要有一个消息发送者对象,并且有一个消息通知的方法让子类继承实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 抽象部分:消息类型的抽象(第一个变化维度)
abstract class Message {
// 桥接:持有发送渠道的引用(连接两个维度)
protected MessageSender sender;

// 通过构造函数注入发送渠道
public Message(MessageSender sender) {
this.sender = sender;
}

// 抽象方法:发送消息(业务逻辑)
public abstract void notify(String content);
}

然后我们实现具体的消息类型

1
2
3
4
5
6
7
8
9
10
11
12
// 扩展抽象1:普通消息
class NormalMessage extends Message {
public NormalMessage(MessageSender sender) {
super(sender);
}

@Override
public void notify(String content) {
// 普通消息直接发送
sender.send(content);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 扩展抽象2:紧急消息
class UrgentMessage extends Message {
public UrgentMessage(MessageSender sender) {
super(sender);
}

@Override
public void notify(String content) {
// 紧急消息添加特殊处理(如重复发送)
String urgentContent = "[紧急] " + content;
sender.send(urgentContent);
sender.send("再次提醒:" + urgentContent); // 紧急消息重复发送
}
}

最后,在客户端调用时的演示如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 客户端:使用桥接模式
public class MessageSystem {
public static void main(String[] args) {
// 创建两个发送渠道(实现部分)
MessageSender smsSender = new SmsSender();
MessageSender emailSender = new EmailSender();

// 创建不同消息类型,并通过构造函数关联发送渠道(桥接)
Message normalSms = new NormalMessage(smsSender);
Message urgentEmail = new UrgentMessage(emailSender);

// 发送消息(客户端无需关心具体组合)
normalSms.notify("您有一条新消息");
urgentEmail.notify("系统将在10分钟后维护");
}
}

从上述的例子中我们可以看出,如果不用桥接模式,为了支持 2 种消息类型 ×2 种发送渠道,需要创建 4 个组合类(NormalSmsMessageNormalEmailMessageUrgentSmsMessageUrgentEmailMessage)。当维度扩展到 3 种消息类型 ×3 种渠道时,需 9 个类,形成 “类爆炸”。

桥接模式通过分离维度,只需3+3=6个类,且新增维度时无需修改原有代码(符合开闭原则)。