桥接模式
桥接模式用于把抽象和实现分离,让两个维度可以独立变化。
一句话理解:一个对象有两个变化方向,不要用继承硬拼,用组合把两个方向拆开。
解决什么问题
假设通知系统有两个变化维度:
- 消息类型:普通消息、告警消息。
- 发送渠道:短信、邮件、钉钉。
如果用继承,类会膨胀:
text
SmsNormalMessage
EmailNormalMessage
DingTalkNormalMessage
SmsAlertMessage
EmailAlertMessage
DingTalkAlertMessage每增加一个消息类型或渠道,类数量都会成倍增长。
桥接模式把两个维度拆开:
text
Message 抽象
-> 持有 Sender
Sender 实现
-> SmsSender
-> EmailSender
-> DingTalkSender基本结构
text
Abstraction -> Implementor
| |
Refined ConcreteImplementor角色:
Abstraction:抽象层,定义高层业务行为。Implementor:实现层接口,定义底层能力。RefinedAbstraction:扩展抽象。ConcreteImplementor:具体实现。
Java 示例
发送渠道:
java
interface MessageSender {
void send(String content);
}
class SmsSender implements MessageSender {
public void send(String content) {
System.out.println("sms: " + content);
}
}
class EmailSender implements MessageSender {
public void send(String content) {
System.out.println("email: " + content);
}
}消息抽象:
java
abstract class Message {
protected final MessageSender sender;
protected Message(MessageSender sender) {
this.sender = sender;
}
abstract void send(String content);
}不同消息类型:
java
class NormalMessage extends Message {
NormalMessage(MessageSender sender) {
super(sender);
}
void send(String content) {
sender.send(content);
}
}
class AlertMessage extends Message {
AlertMessage(MessageSender sender) {
super(sender);
}
void send(String content) {
sender.send("[ALERT] " + content);
}
}使用:
java
Message message = new AlertMessage(new SmsSender());
message.send("disk usage is over 90%");如果新增钉钉渠道,只需要新增 DingTalkSender。如果新增紧急消息,只需要新增 UrgentMessage。
使用场景
- 多个维度独立变化。
- 类继承层级已经开始爆炸。
- 需要运行时组合不同实现。
- 业务抽象和底层实现都可能变化。
优点
- 避免继承层级过深。
- 抽象和实现可以独立扩展。
- 运行时可以灵活组合。
- 更符合合成复用原则。
缺点
- 初学时理解成本较高。
- 需要提前识别变化维度。
- 简单场景使用会显得过度设计。
和策略模式的区别
桥接和策略都使用组合,但关注点不同:
| 模式 | 关注点 |
|---|---|
| 桥接 | 拆分两个长期独立变化的维度 |
| 策略 | 在一组算法或规则中选择一种执行 |
桥接更偏结构设计,策略更偏行为选择。
实战注意
不要一看到两个实现就用桥接。只有当两个方向都会持续扩展,并且继承已经让类数量变多时,桥接才真正有价值。