什么是Java桥接模式
Java桥接模式属于结构型设计模式的一种,核心设计思想是将抽象部分与它的实现部分分离,让两者都可以独立地进行变化,避免抽象和实现的强耦合。通常我们会把具有两个或多个独立变化维度的业务场景,通过桥接模式拆分成不同的抽象层次和实现层次,再通过桥接关系组合起来。

桥接模式的核心角色
- 抽象化角色(Abstraction):定义抽象类的接口,维护一个指向实现化对象的引用
- 扩展抽象化角色(RefinedAbstraction):是抽象化角色的子类,实现父类中的业务方法,调用实现化角色中的业务方法
- 实现化角色(Implementor):定义实现类的接口,供抽象化角色调用
- 具体实现化角色(ConcreteImplementor):实现实现化角色的接口,给出具体的实现逻辑
简单代码示例
以消息发送场景为例,消息类型(普通消息、紧急消息)和发送渠道(邮件、短信)是两个独立变化的维度,适合用桥接模式实现:
// 实现化角色:消息发送渠道接口
public interface MessageSender {
void send(String message);
}
// 具体实现化角色:邮件发送
public class EmailSender implements MessageSender {
@Override
public void send(String message) {
System.out.println("通过邮件发送消息:" + message);
}
}
// 具体实现化角色:短信发送
public class SmsSender implements MessageSender {
@Override
public void send(String message) {
System.out.println("通过短信发送消息:" + message);
}
}
// 抽象化角色:消息抽象类
public abstract class AbstractMessage {
// 桥接关系:持有实现化角色的引用
protected MessageSender messageSender;
public AbstractMessage(MessageSender messageSender) {
this.messageSender = messageSender;
}
// 抽象发送方法
public abstract void sendMessage(String message);
}
// 扩展抽象化角色:普通消息
public class CommonMessage extends AbstractMessage {
public CommonMessage(MessageSender messageSender) {
super(messageSender);
}
@Override
public void sendMessage(String message) {
System.out.println("发送普通消息:");
messageSender.send(message);
}
}
// 扩展抽象化角色:紧急消息
public class UrgentMessage extends AbstractMessage {
public UrgentMessage(MessageSender messageSender) {
super(messageSender);
}
@Override
public void sendMessage(String message) {
System.out.println("发送紧急消息:");
messageSender.send("[紧急]" + message);
}
}
// 测试类
public class BridgeTest {
public static void main(String[] args) {
// 普通消息通过邮件发送
MessageSender emailSender = new EmailSender();
AbstractMessage commonEmailMessage = new CommonMessage(emailSender);
commonEmailMessage.sendMessage("本周周会时间调整为周五下午三点");
// 紧急消息通过短信发送
MessageSender smsSender = new SmsSender();
AbstractMessage urgentSmsMessage = new UrgentMessage(smsSender);
urgentSmsMessage.sendMessage("服务器出现宕机,请立即处理");
}
}
Java桥接模式的优点
1. 符合开闭原则,扩展性强
当需要新增消息类型时,只需要新增扩展抽象化角色的子类,不需要修改原有的实现化角色代码;当需要新增发送渠道时,只需要新增实现化角色的子类,不需要修改抽象层的代码。比如上面的例子中,如果要新增微信发送渠道,只需要新增一个WechatSender类实现MessageSender接口即可,原有代码完全不需要改动。
2. 解耦抽象与实现,降低耦合度
桥接模式通过组合关系替代了传统的继承关系,避免了抽象类和实现类的强绑定。如果采用继承实现,普通邮件消息、普通短信消息、紧急邮件消息、紧急短信消息需要四个子类,而桥接模式只需要2个抽象子类和2个实现子类,大大减少了类的数量,也避免了多层继承带来的类爆炸问题。
3. 提升代码复用性
实现化角色的代码可以被多个不同的抽象化角色复用,比如上面的EmailSender可以同时被普通消息和紧急消息使用,不需要为每个消息类型单独编写邮件发送的逻辑,减少了重复代码。
4. 符合单一职责原则
抽象化角色只负责处理抽象层的业务逻辑,实现化角色只负责处理具体实现的业务逻辑,两者的职责划分清晰,后续维护时更容易定位问题。
Java桥接模式的缺点
1. 增加系统复杂度
桥接模式需要额外定义抽象层和实现层的接口,同时需要维护两者之间的桥接关系,对于简单的业务场景来说,会引入不必要的复杂度。如果业务只有一个变化维度,使用桥接模式反而会让代码变得更难理解,增加维护成本。
2. 设计难度较高
使用桥接模式的前提是正确识别出系统中独立变化的维度,如果维度识别错误,比如把两个关联度很高的维度拆分开,反而会导致代码逻辑混乱。对于经验不足的开发者来说,很难在前期就准确判断出哪些维度是独立变化的,容易出现设计偏差。
3. 增加调试难度
由于抽象层和实现层是分离的,调用链路会比直接继承更长,出现问题时需要同时排查抽象层和实现层的代码,调试的链路更长,定位问题的成本更高。
适用场景建议
如果你的业务场景中存在两个或多个独立变化的维度,且这两个维度都需要独立扩展,那么桥接模式是非常合适的选择。比如图形绘制场景中,形状和颜色是两个独立维度;数据库操作场景中,数据库类型和操作类型是独立维度,都可以用桥接模式实现。如果业务只有一个变化维度,或者变化维度之间耦合度很高,不建议使用桥接模式,避免不必要的复杂度。