设计模式-桥接模式02
一、什么是“抽象部分”与“实现部分”?
- 抽象部分:指的是系统中“高层逻辑”或“业务需求”层面,比如“消息”是什么、“图形”是什么。它定义了系统的行为和接口,关注的是“做什么”。
- 实现部分:指的是抽象部分的具体实现方式,比如“消息怎么发”、“图形怎么画”。它关注的是“怎么做”。
传统面向对象编程中,通常使用继承将抽象和实现结合在一起。例如:
abstract class Shape { // 抽象部分abstract void draw(); // 实现部分
}class Circle extends Shape {void draw() { /* 画圆的具体实现 */ }
}
这种方式,抽象和实现是紧密耦合的。
二、为什么要分离?
1. 多维度扩展的问题
假如系统有两套变化维度(比如“图形类型”与“绘制方式”),用继承会导致类爆炸:
- 圆形(Circle)、方形(Square)
- 矢量绘制(VectorDraw)、位图绘制(RasterDraw)
如果用继承表达,每种图形和每种绘制方式都要有一个类,共计 2 × 2 = 4 个类:
- VectorCircle
- VectorSquare
- RasterCircle
- RasterSquare
如果再加一个维度,类数量呈指数增长,维护困难。
2. 灵活性不足
如果你希望在运行时动态切换实现方式,继承无法做到,只能通过组合。
三、桥接模式的分离方式
桥接模式通过组合(has-a)而非继承(is-a),让抽象和实现分别独立扩展。
1. 抽象部分
定义高层接口,持有实现部分的引用(通常是接口或抽象类)。
abstract class Shape {protected DrawAPI drawAPI; // 实现部分public Shape(DrawAPI drawAPI) {this.drawAPI = drawAPI;}public abstract void draw();
}
2. 实现部分
定义实现接口和具体实现类。
interface DrawAPI {void drawCircle(int radius, int x, int y);
}class VectorDrawAPI implements DrawAPI { /* ... */ }
class RasterDrawAPI implements DrawAPI { /* ... */ }
3. 组合连接
抽象部分和实现部分通过引用组合在一起,可以任意组合。
class Circle extends Shape {private int x, y, radius;public Circle(int x, int y, int radius, DrawAPI drawAPI) {super(drawAPI);this.x = x; this.y = y; this.radius = radius;}public void draw() {drawAPI.drawCircle(radius, x, y);}
}
客户端:
Shape circle1 = new Circle(1, 2, 3, new VectorDrawAPI());
Shape circle2 = new Circle(4, 5, 6, new RasterDrawAPI());
circle1.draw();
circle2.draw();
四、分离带来的好处
-
抽象部分与实现部分可以独立扩展
增加新的抽象(如新的图形类型),只需继承抽象部分;
增加新的实现(如新的绘制方式),只需扩展实现接口。 -
灵活组合
抽象和实现通过组合连接,可以在运行时任意组合,极大增强了系统的灵活性。 -
降低耦合,增强可维护性
抽象和实现互不影响,修改实现不会影响抽象,反之亦然。 -
应对多维度变化
两个维度的变化不再相互影响,避免了继承导致的类爆炸。
五、总结
“将抽象部分与实现部分分离”,就是让高层业务逻辑(抽象)和底层实现细节(实现)各自独立发展,通过桥接(组合)方式连接起来。这样既解决了多维度变化带来的复杂性,又提升了系统的灵活性和可扩展性。