桥接模式
桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。
这种模式涉及到一个作为桥接的接口,使得实体类的功能独立于接口实现类,这两种类型的类可被结构化改变而互不影响。
桥接模式的目的是将抽象与实现分离,使它们可以独立地变化,该模式通过将一个对象的抽象部分与它的实现部分分离,使它们可以独立地改变。它通过组合的方式,而不是继承的方式,将抽象和实现的部分连接起来。这对于避免类爆炸问题和实现灵活的代码结构非常有用。
介绍
意图:将抽象部分与实现部分分离,使它们都可以独立的变化。
主要解决:在有多种可能会变化的情况下,用继承会造成类爆炸问题,扩展起来不灵活。
何时使用:实现系统可能有多个角度分类,每一种角度都可能变化。
如何解决:把这种多角度分类分离出来,让它们独立变化,减少它们之间耦合。
关键代码:抽象类依赖实现类。
应用实例: 1、猪八戒从天蓬元帅转世投胎到猪,转世投胎的机制将尘世划分为两个等级,即:灵魂和肉体,前者相当于抽象化,后者相当于实现化。生灵通过功能的委派,调用肉体对象的功能,使得生灵可以动态地选择。 2、墙上的开关,可以看到的开关是抽象的,不用管里面具体怎么实现的。
优点: 1、抽象和实现的分离。 2、优秀的扩展能力。 3、实现细节对客户透明。
缺点:桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。
使用场景: 1、如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。 2、对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。 3、一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
注意事项:对于两个独立变化的维度,使用桥接模式再适合不过了。
以下是桥接模式的几个关键角色:
- 抽象(Abstraction):定义抽象接口,通常包含对实现接口的引用。
- 扩展抽象(Refined Abstraction):对抽象的扩展,可以是抽象类的子类或具体实现类。
- 实现(Implementor):定义实现接口,提供基本操作的接口。
- 具体实现(Concrete Implementor):实现具体的实现部分。
C++代码实现
下面通过一个简单的例子展示如何在C++中实现桥接模式。假设我们有一个图形类层次结构,其中包括不同类型的形状(如圆形和矩形)和不同的绘制实现(如SVG和Canvas)。
实现接口
首先,我们定义一个实现接口 DrawingImplementor
:
class DrawingImplementor {
public:
virtual ~DrawingImplementor() = default;
virtual void drawCircle(double x, double y, double radius) = 0;
virtual void drawRectangle(double x, double y, double width, double height) = 0;
};
具体实现
接下来,我们实现具体的实现类 SVGImplementor
和 CanvasImplementor
:
class SVGImplementor : public DrawingImplementor {
public:
void drawCircle(double x, double y, double radius) override {
std::cout << "Drawing Circle in SVG at (" << x << ", " << y << ") with radius " << radius << std::endl;
}
void drawRectangle(double x, double y, double width, double height) override {
std::cout << "Drawing Rectangle in SVG at (" << x << ", " << y << ") with width " << width << " and height " << height << std::endl;
}
};
class CanvasImplementor : public DrawingImplementor {
public:
void drawCircle(double x, double y, double radius) override {
std::cout << "Drawing Circle on Canvas at (" << x << ", " << y << ") with radius " << radius << std::endl;
}
void drawRectangle(double x, double y, double width, double height) override {
std::cout << "Drawing Rectangle on Canvas at (" << x << ", " << y << ") with width " << width << " and height " << height << std::endl;
}
};
抽象类
我们定义一个抽象类 Shape
,它持有一个 DrawingImplementor
的引用:
class Shape {
protected:
DrawingImplementor* implementor;
public:
Shape(DrawingImplementor* impl) : implementor(impl) {}
virtual ~Shape() = default;
virtual void draw() = 0;
};
细化抽象
然后,我们定义具体的形状类 Circle
和 Rectangle
:
class Circle : public Shape {
private:
double x, y, radius;
public:
Circle(DrawingImplementor* impl, double x, double y, double radius)
: Shape(impl), x(x), y(y), radius(radius) {}
void draw() override {
implementor->drawCircle(x, y, radius);
}
};
class Rectangle : public Shape {
private:
double x, y, width, height;
public:
Rectangle(DrawingImplementor* impl, double x, double y, double width, double height)
: Shape(impl), x(x), y(y), width(width), height(height) {}
void draw() override {
implementor->drawRectangle(x, y, width, height);
}
};
客户端代码
最后,我们在客户端代码中使用这些类:
#include <iostream>
int main() {
DrawingImplementor* svgImpl = new SVGImplementor();
DrawingImplementor* canvasImpl = new CanvasImplementor();
Shape* circleSVG = new Circle(svgImpl, 10, 10, 5);
Shape* rectangleSVG = new Rectangle(svgImpl, 20, 20, 10, 5);
Shape* circleCanvas = new Circle(canvasImpl, 15, 15, 7);
Shape* rectangleCanvas = new Rectangle(canvasImpl, 25, 25, 12, 6);
circleSVG->draw();
rectangleSVG->draw();
circleCanvas->draw();
rectangleCanvas->draw();
delete circleSVG;
delete rectangleSVG;
delete circleCanvas;
delete rectangleCanvas;
delete svgImpl;
delete canvasImpl;
return 0;
}
输出结果:
Drawing Circle in SVG at (10, 10) with radius 5
Drawing Rectangle in SVG at (20, 20) with width 10 and height 5
Drawing Circle on Canvas at (15, 15) with radius 7
Drawing Rectangle on Canvas at (25, 25) with width 12 and height 6
总结
桥接模式通过将抽象部分与实现部分分离,提供了一种灵活的结构来应对变化。通过这种模式,可以更容易地扩展和维护代码,而无需担心引入复杂的依赖关系。在C++中,通过组合和继承,我们可以轻松地实现桥接模式,从而创建灵活且可扩展的系统。希望本文的介绍和示例能够帮助读者理解并应用这一设计模式。