什么是桥接模式?
桥接模式(Bridge Pattern)是一种结构型设计模式,它的核心目的是解耦 抽象部分和实现部分,让它们可以独立变化。在简单的描述中,桥接模式可以让你在不修改原有代码的情况下,分别改变抽象的功能 和具体的实现。
假设你正在开发一个图形绘制程序,它涉及到多个图形(比如圆形、方形)和不同的绘制方式(如屏幕绘制、打印机绘制)。如果将所有图形和绘制方式写在一起,每次新增图形或绘制方式时,都需要修改很多代码,这样不仅增加了复杂性,还不容易维护。
桥接模式的解决思路是:将**图形(抽象)和绘制方式(实现)**分开,给每一部分提供独立的变化空间。这样,添加新的图形或新的绘制方式时,只需要扩展新的类即可,而不需要修改现有的代码。
桥接模式的结构
桥接模式的关键在于将抽象层 和实现层分开,通过"桥"将它们连接起来。它有两个主要组成部分:
- 抽象部分:表示具体的功能或对象,比如图形类型(圆形、方形等)。
- 实现部分:表示具体的实现方式,比如绘制图形的具体方法(屏幕绘制、打印机绘制等)。
这两个部分是独立的,它们通过桥接连接,从而能够独立发展和变化。
桥接模式的代码示例
为了更好地理解桥接模式,我们来做一个简单的图形绘制程序,支持不同的图形(圆形、方形)和不同的绘制方式(屏幕绘制、打印机绘制)。我们将通过桥接模式来解耦这两个方面。
cpp
#include <iostream>
#include <string>
// 绘图接口(实现类接口)
class DrawingAPI {
public:
virtual void drawCircle(double x, double y, double radius) = 0;
virtual ~DrawingAPI() = default;
};
// 具体实现:屏幕绘制
class ScreenDrawingAPI : public DrawingAPI {
public:
void drawCircle(double x, double y, double radius) override {
std::cout << "在屏幕上绘制圆形,位置: (" << x << ", " << y << "), 半径: " << radius << std::endl;
}
};
// 具体实现:打印机绘制
class PrinterDrawingAPI : public DrawingAPI {
public:
void drawCircle(double x, double y, double radius) override {
std::cout << "在打印机上绘制圆形,位置: (" << x << ", " << y << "), 半径: " << radius << std::endl;
}
};
// 图形类(抽象类)
class Shape {
protected:
DrawingAPI* drawingAPI; // 这里持有一个指向绘图实现类的指针
public:
Shape(DrawingAPI* api) : drawingAPI(api) {} // 通过构造函数注入具体实现类
virtual void draw() = 0; // 绘制图形的接口
virtual void resize(double factor) = 0; // 调整图形大小
virtual ~Shape() = default;
};
// 扩展的具体图形类:圆形
class Circle : public Shape {
private:
double x, y, radius; // 圆形的坐标和半径
public:
Circle(double x, double y, double radius, DrawingAPI* api)
: Shape(api), x(x), y(y), radius(radius) {}
void draw() override {
drawingAPI->drawCircle(x, y, radius); // 将绘制任务委托给具体实现
}
void resize(double factor) override {
radius *= factor; // 调整圆形的半径
}
};
int main() {
ScreenDrawingAPI screenAPI; // 创建屏幕绘制实现
PrinterDrawingAPI printerAPI; // 创建打印机绘制实现
// 创建圆形对象,使用不同的绘制方式
Circle circle1(1, 2, 3, &screenAPI); // 在屏幕上绘制
Circle circle2(5, 6, 4, &printerAPI); // 在打印机上绘制
circle1.draw(); // 屏幕绘制圆形
circle2.draw(); // 打印机绘制圆形
circle1.resize(2.0); // 改变圆形大小
circle1.draw(); // 再次绘制,使用屏幕绘制
return 0;
}
代码讲解
让我们来逐步分析这段代码,理解桥接模式如何起作用。
1. 绘图接口(DrawingAPI
)
cpp
class DrawingAPI {
public:
virtual void drawCircle(double x, double y, double radius) = 0;
virtual ~DrawingAPI() = default;
};
DrawingAPI
是一个抽象接口,它定义了绘制图形的方法 drawCircle
。具体的绘制方式(如屏幕绘制或打印机绘制)需要实现这个接口。
2. 具体的绘图实现(ScreenDrawingAPI
和 PrinterDrawingAPI
)
cpp
class ScreenDrawingAPI : public DrawingAPI {
public:
void drawCircle(double x, double y, double radius) override {
std::cout << "在屏幕上绘制圆形,位置: (" << x << ", " << y << "), 半径: " << radius << std::endl;
}
};
class PrinterDrawingAPI : public DrawingAPI {
public:
void drawCircle(double x, double y, double radius) override {
std::cout << "在打印机上绘制圆形,位置: (" << x << ", " << y << "), 半径: " << radius << std::endl;
}
};
这两个类分别实现了 DrawingAPI
接口,提供了不同的绘制方式:ScreenDrawingAPI
在屏幕上绘制圆形,而 PrinterDrawingAPI
在打印机上绘制圆形。
3. 抽象类(Shape
)
cpp
class Shape {
protected:
DrawingAPI* drawingAPI; // 持有一个绘图实现类的指针
public:
Shape(DrawingAPI* api) : drawingAPI(api) {} // 通过构造函数注入具体的绘图实现
virtual void draw() = 0; // 绘制图形的接口
virtual void resize(double factor) = 0; // 调整图形大小
};
Shape
是一个抽象类,定义了所有图形(如圆形、方形)的共同接口:draw()
和 resize()
。它通过持有 DrawingAPI
指针将具体的绘制任务委托给实现类,从而将图形抽象部分与绘制实现部分分开。
4. 具体图形类(Circle
)
cpp
class Circle : public Shape {
private:
double x, y, radius; // 圆形的坐标和半径
public:
Circle(double x, double y, double radius, DrawingAPI* api)
: Shape(api), x(x), y(y), radius(radius) {}
void draw() override {
drawingAPI->drawCircle(x, y, radius); // 调用具体绘图实现的drawCircle方法
}
void resize(double factor) override {
radius *= factor; // 改变圆形的半径
}
};
Circle
类继承自 Shape
,并实现了 draw()
和 resize()
方法。它将图形绘制的任务委托给 drawingAPI
,从而实现了图形的抽象和绘制方式的解耦。
5. 客户端代码
在 main
函数中,我们创建了两个 Circle
对象,分别使用了 ScreenDrawingAPI
和 PrinterDrawingAPI
作为绘制实现。通过调用 circle1.draw()
和 circle2.draw()
,我们看到两种不同的绘制方式。
cpp
int main() {
ScreenDrawingAPI screenAPI; // 屏幕绘制实现
PrinterDrawingAPI printerAPI; // 打印机绘制实现
// 创建两个圆形对象,分别使用不同的绘制方式
Circle circle1(1, 2, 3, &screenAPI);
Circle circle2(5, 6, 4, &printerAPI);
circle1.draw(); // 屏幕绘制圆形
circle2.draw(); // 打印机绘制圆形
circle1.resize(2.0); // 改变圆形大小
circle1.draw(); // 再次绘制,使用屏幕绘制
return 0;
}
总结
桥接模式的核心思想就是解耦抽象和实现部分,它们可以独立变化,而不相互影响。在这个例子中,图形类(
如 Circle
)和绘图方式(如 ScreenDrawingAPI
和 PrinterDrawingAPI
)通过桥接模式分离开来,增加新的图形类型或绘制方式时,我们只需要扩展新类,而不需要修改现有代码。这样做让系统更加灵活和可扩展。
完整代码
cpp
#include <iostream>
#include <string>
// 绘图接口(实现类接口)
class DrawingAPI {
public:
virtual void drawCircle(double x, double y, double radius) = 0;
virtual ~DrawingAPI() = default;
};
// 具体实现:屏幕绘制
class ScreenDrawingAPI : public DrawingAPI {
public:
void drawCircle(double x, double y, double radius) override {
std::cout << "在屏幕上绘制圆形,位置: (" << x << ", " << y << "), 半径: " << radius << std::endl;
}
};
// 具体实现:打印机绘制
class PrinterDrawingAPI : public DrawingAPI {
public:
void drawCircle(double x, double y, double radius) override {
std::cout << "在打印机上绘制圆形,位置: (" << x << ", " << y << "), 半径: " << radius << std::endl;
}
};
// 图形类(抽象类)
class Shape {
protected:
DrawingAPI* drawingAPI; // 这里持有一个指向绘图实现类的指针
public:
Shape(DrawingAPI* api) : drawingAPI(api) {} // 通过构造函数注入具体实现类
virtual void draw() = 0; // 绘制图形的接口
virtual void resize(double factor) = 0; // 调整图形大小
virtual ~Shape() = default;
};
// 扩展的具体图形类:圆形
class Circle : public Shape {
private:
double x, y, radius; // 圆形的坐标和半径
public:
Circle(double x, double y, double radius, DrawingAPI* api)
: Shape(api), x(x), y(y), radius(radius) {}
void draw() override {
drawingAPI->drawCircle(x, y, radius); // 将绘制任务委托给具体实现
}
void resize(double factor) override {
radius *= factor; // 调整圆形的半径
}
};
int main() {
ScreenDrawingAPI screenAPI; // 创建屏幕绘制实现
PrinterDrawingAPI printerAPI; // 创建打印机绘制实现
// 创建圆形对象,使用不同的绘制方式
Circle circle1(1, 2, 3, &screenAPI); // 在屏幕上绘制
Circle circle2(5, 6, 4, &printerAPI); // 在打印机上绘制
// 绘制圆形
circle1.draw(); // 屏幕绘制圆形
circle2.draw(); // 打印机绘制圆形
// 调整圆形大小
circle1.resize(2.0); // 改变圆形大小
circle1.draw(); // 再次绘制,使用屏幕绘制
return 0;
}
结果输出:
在屏幕上绘制圆形,位置: (1, 2), 半径: 3
在打印机上绘制圆形,位置: (5, 6), 半径: 4
在屏幕上绘制圆形,位置: (1, 2), 半径: 6
这个实现展示了如何使用桥接模式解耦图形的抽象(Shape
)和具体的绘制实现(DrawingAPI
),让你可以独立地扩展图形类型和绘制方式,而不影响已有的代码结构。
本文由mdnice多平台发布