桥接模式有哪些角色?调用流程是什么?
简化版
桥接模式主要有四类角色:抽象类、扩展抽象类、实现接口、具体实现类。调用流程是客户端创建具体实现对象,再把它注入抽象对象,业务方法由抽象对象发起,底层细节委托给实现接口完成。
详细版
桥接模式的角色可以这样理解:
- Abstraction:抽象部分,定义高层业务接口,内部持有 Implementor。
- RefinedAbstraction:扩展抽象部分,在抽象基础上加入更具体的业务语义。
- Implementor:实现部分接口,定义底层能力。
- ConcreteImplementor:具体实现类,完成真正的底层操作。
以消息系统为例:
Message是抽象部分。UrgentMessage是扩展抽象部分。MessageSender是实现接口。SmsSender、EmailSender是具体实现类。
调用时,客户端可以创建 new UrgentMessage(new SmsSender())。调用 send() 后,紧急消息先处理自己的业务规则,再调用 sender.send() 完成渠道发送。
完整版教学
一、Abstraction:抽象部分
Abstraction 是桥接模式面向客户端的一侧。它负责定义业务上看得见的操作,同时持有一个实现接口引用。
例如:
abstract class Message {
protected final MessageSender sender;
protected Message(MessageSender sender) {
this.sender = sender;
}
public abstract void send(String content, String to);
}
这里 Message 并不关心短信、邮件、站内信怎么发。它只关心“发送消息”这个业务动作。
二、RefinedAbstraction:扩展抽象部分
RefinedAbstraction 是 Abstraction 的具体业务变体。它可以在调用实现接口之前或之后加入自己的业务逻辑。
例如紧急消息可以自动追加紧急标识:
class UrgentMessage extends Message {
public UrgentMessage(MessageSender sender) {
super(sender);
}
@Override
public void send(String content, String to) {
sender.send("[紧急] " + content, to);
}
}
新增 NormalMessage、VerifyCodeMessage 时,不需要修改短信或邮件发送类。
三、Implementor:实现接口
Implementor 是桥接模式的另一侧。它定义的是底层实现能力,而不是高层业务语义。
interface MessageSender {
void send(String content, String to);
}
这个接口越稳定,桥接模式越好用。抽象部分依赖它,具体实现类围绕它扩展。
四、ConcreteImplementor:具体实现类
ConcreteImplementor 负责把接口落地:
class SmsSender implements MessageSender {
@Override
public void send(String content, String to) {
System.out.println("短信发送给 " + to + ": " + content);
}
}
class EmailSender implements MessageSender {
@Override
public void send(String content, String to) {
System.out.println("邮件发送给 " + to + ": " + content);
}
}
新增发送渠道时,只新增实现类,不影响消息类型。
五、完整调用链
一次调用大致是:
- 客户端选择具体实现,例如
SmsSender。 - 客户端选择高层抽象,例如
UrgentMessage。 - 把实现对象传给抽象对象。
- 调用抽象对象的业务方法。
- 抽象对象处理业务语义。
- 抽象对象委托实现接口完成底层动作。
这个流程的关键点是:客户端组装对象,抽象层负责业务,实现层负责能力。
六、角色之间的依赖方向
桥接模式推荐的依赖方向是:
- 高层抽象依赖实现接口。
- 具体抽象不依赖具体实现。
- 具体实现不反向依赖高层抽象。
如果具体实现类反过来知道很多业务抽象细节,桥就会变成双向耦合,维护成本会明显上升。
七、常见误区与追问
运行流程应从客户端装配一路追到具体实现。客户端选择1个 RefinedAbstraction 和1个 ConcreteImplementor,前者保存后者的接口引用;业务方法执行时先处理高层语义,再委托底层操作。新增角色时只应进入所属一侧,不应跨到另一侧修改分派。
| 检查维度 | 判定依据 |
|---|---|
| RefinedAbstraction | 扩展高层行为并委托 |
| ConcreteImplementor | 完成平台或能力细节 |
Client -> RefinedAbstraction => Implementor -> ConcreteImplementor
记忆钩子:客户端负责搭桥,抽象侧过桥,实现侧落地。
- 误区:Client 每次调用都必须重新选实现。 实现通常在构造或配置阶段注入,可在对象生命周期内保持稳定。
- 追问:Abstraction 能否组合多个 Implementor? 可以,但应确保每个接口代表清晰独立的能力维度。
- 误区:ConcreteImplementor 负责高层业务流程。 它应聚焦底层实现,高层编排属于 Abstraction。
- 追问:角色间最重要的依赖是什么? Abstraction 只依赖 Implementor 抽象,不依赖具体实现类。
- 追问:怎么做流程级测试? 用不同实现运行同一抽象,再用同一实现运行不同抽象,验证两轴组合。
八、加强记忆
桥接模式的角色可以记成“业务一侧 + 能力一侧”:Abstraction 和 RefinedAbstraction 管业务语义,Implementor 和 ConcreteImplementor 管底层能力,中间用一个接口引用连接起来。