桥接模式
桥接模式是一种结构型设计模式 (Structural Pattern),它将抽象部分 (Abstraction) 与它的实现部分 (Implementation) 分离,使它们可以独立地变化。
**特点 **
- 解耦抽象与实现:核心特点是将继承关系转换为组合/聚合关系,从而解耦抽象和实现。
- 高内聚,低耦合:抽象和实现可以独立地进行扩展和修改,互不影响。
- 提高可扩展性:在两个独立的维度(抽象和实现)上都可以自由地增加新的子类,而不会导致类数量急剧膨胀(避免了类爆炸)。
- 符合开闭原则:对扩展开放,对修改关闭。增加新的抽象或新的实现通常不需要修改现有代码。
- 客户端透明:客户端通过统一的抽象接口与对象交互,无需关心具体的实现细节。
**核心组成 **
- 抽象 (Abstraction):
- 定义抽象接口,并包含一个对实现者接口的引用。
- 客户端通过此接口与具体实现进行交互。
- 精炼抽象 (Refined Abstraction):
- 继承自
Abstraction
,是Abstraction
的具体实现或扩展。 - 可以添加新的行为或覆盖父类方法。
- 继承自
- 实现者接口 (Implementor):
- 定义实现类的接口。这个接口不一定要与
Abstraction
的接口一致,通常提供更基本的操作。 - 它是实现层次的顶层接口。
- 定义实现类的接口。这个接口不一定要与
- 具体实现者 (Concrete Implementor):
- 实现
Implementor
接口,在不同平台上实现Implementor
接口的具体功能。
- 实现
**核心思想 **
“组合优于继承”。当一个系统可能存在多个维度的变化(例如,一个图形既有形状变化,又有颜色/渲染方式变化),如果使用继承,会导致类的数量呈指数级增长(如 RedCircle
, RedSquare
, BlueCircle
, BlueSquare
...)。桥接模式通过将其中一个维度(通常是实现维度,如颜色/渲染方式)分离出来,形成独立的层次,并在抽象层次中持有对实现层次的引用,从而将两个维度解耦。这样,增加一种新形状或一种新颜色,都只需要增加一个类,而不会影响另一个维度。
合成/聚合复用原则
- 组合(Composition)与聚合(Aggregation): 这两种都是“has-a”(有一个)的关系。一个类通过持有另一个类的实例作为自己的成员变量来使用其功能。
- 组合 表示强拥有关系,整体和部分同生共死(如:发动机是汽车的一部分,汽车销毁,发动机也销毁)。
- 聚合 表示弱拥有关系,整体和部分可以独立存在(如:汽车和司机,司机可以更换)。
- 继承(Inheritance): 这是一种“is-a”(是一个)的关系。子类会获得父类的属性和方法。
为什么推荐组合/聚合?
- 降低耦合度: 组合/聚合的耦合度远低于继承。继承会将子类与父类紧密耦合,父类的任何修改都可能影响所有子类。而组合/聚合的类之间关系更松散,修改一个类对另一个类的影响较小。
- 更高的灵活性: 可以在运行时动态地改变组合/聚合的对象,从而改变行为。继承则是在编译时静态决定的。
- 避免继承的缺点: 继承容易导致类层次结构复杂、僵化,并且子类会不必要地暴露父类的接口和实现细节。
当需要复用某个功能时,优先考虑让一个类“包含”另一个能提供该功能的类(组合/聚合),而不是让这个类“成为”那个类的子类(继承)。这能让代码更灵活、更易维护和扩展。
使用场景
场景描述 | 说明 |
---|---|
存在多个独立变化的维度 | 当一个类存在两个或多个独立变化的维度(如产品类型和制造方式、图形形状和渲染引擎、消息类型和发送渠道),且都需要扩展时。 |
避免继承体系的类爆炸 | 当使用多层继承会导致子类数量急剧增加,形成复杂的继承树时。 |
希望抽象和实现都能独立扩展 | 当需要让抽象部分和实现部分可以独立地进行修改和扩展,而互不影响。 |
实现细节对客户端透明 | 希望客户端代码不依赖于具体的实现,只通过抽象接口进行操作。 |
运行时绑定实现 | 需要在运行时动态地切换对象的具体实现。 |
示例:
抽象化接口(发送消息)
java
public interface MessageSend {
String sendMessage(String message);
}
具体实现者(实现发送不同平台信息)
java
public class EmailSend implements MessageSend {
@Override
public String sendMessage(String message) {
return "Email send message: " + message;
}
}
java
public class WeChatSend implements MessageSend {
@Override
public String sendMessage(String message) {
return "WeChat send message: " + message;
}
}
java
public class QQSend implements MessageSend {
@Override
public String sendMessage(String message) {
return "QQ send message: " + message;
}
}
精炼抽象(抽象信息对象)
java
@AllArgsConstructor
public abstract class Message {
protected MessageSend messageSend;
public abstract String send(String message);
}
实现者(不同的信息类型)
java
public class NoticeMessage extends Message {
public NoticeMessage(MessageSend messageSend) {
super(messageSend);
}
@Override
public String send(String message) {
return "通知信息: " + messageSend.sendMessage(message);
}
}
java
public class SystemMessage extends Message{
public SystemMessage(MessageSend messageSend) {
super(messageSend);
}
@Override
public String send(String message) {
return "系统信息: " + messageSend.sendMessage(message);
}
}