设计模式-11 - Bridge Method 桥接模式
1.定义
桥接模式是一种设计模式,它将抽象部分与其实现部分分离,使它们可以独立变化。它允许你改变抽象部分和实现部分的实现,而无需更改它们的接口。
结构:
桥接模式涉及四个主要角色:
- 抽象(Abstraction):定义抽象接口,客户端代码与之交互。
- 实现(Implementor):实现抽象接口并提供具体行为。
- 扩展抽象(Refined Abstraction):扩展抽象接口,提供更加具体的接口。
- 具体实现(Concrete Implementor):实现扩展抽象接口并提供具体的实现。
一个常见的桥接模式示例是图形绘制库。抽象接口可以定义绘制不同形状的方法,而实现对象可以提供不同平台(例如 Windows 或 macOS)的具体绘制实现。这允许开发人员使用相同的抽象接口在不同平台上绘制形状,而无需更改代码。
2.内涵
桥接模式工作原理
- 客户端代码通过抽象接口与桥接模式交互。
- 抽象接口将请求委托给实现对象。
- 实现对象执行请求并返回结果。
- 桥接模式允许在不改变抽象接口的情况下改变实现。
- 还可以扩展抽象接口和具体实现,以提供新的功能或行为。
桥接模式核心组件及调用关系 ASCII 图
+----------------+
| Abstraction |
+----------------+
|
v
+-----------------------+------------------+
| RefinedAbstraction1 | RefinedAbstraction2 |
+--------------+-----------------------------+
| |
v v
+--------------+ +--------------+
| ConcreteImplementor1 | | ConcreteImplementor2 |
+--------------+ +--------------+
调用关系:
客户端代码通过 RefinedAbstraction 类与 Abstraction 类进行交互。
RefinedAbstraction 类将调用委托给其关联的 ConcreteImplementor 类。
组件说明:
Abstraction:定义抽象接口,它定义了客户端代码与桥接模式交互的方式。
RefinedAbstraction:扩展 Abstraction 接口,为特定的实现提供不同的行为。
ConcreteImplementor:实现 Abstraction 接口,提供具体的实现细节。
3.使用示例
#include <iostream>
// Abstraction: Shape
class Shape {
public:
virtual void draw() = 0;
};
// Implementations: Renderer (VectorRenderer and
// RasterRenderer)
class Renderer {
public:
virtual void render() = 0;
};
class VectorRenderer : public Renderer {
public:
void render() override
{
std::cout << "Rendering as a vector\n";
}
};
class RasterRenderer : public Renderer {
public:
void render() override
{
std::cout << "Rendering as a raster\n";
}
};
// Concrete Abstractions: Circle and Square
class Circle : public Shape {
public:
Circle(Renderer& renderer)
: renderer(renderer)
{
}
void draw() override
{
std::cout << "Drawing a circle ";
renderer.render();
}
private:
Renderer& renderer;
};
class Square : public Shape {
public:
Square(Renderer& renderer)
: renderer(renderer)
{
}
void draw() override
{
std::cout << "Drawing a square ";
renderer.render();
}
private:
Renderer& renderer;
};
int main()
{
VectorRenderer vectorRenderer;
RasterRenderer rasterRenderer;
Circle circle(vectorRenderer);
Square square(rasterRenderer);
circle.draw(); // Output: Drawing a circle Rendering as
// a vector
square.draw(); // Output: Drawing a square Rendering as
// a raster
return 0;
}
4.注意事项
桥接模式注意事项:
- 复杂性:桥接模式引入了额外的抽象层,这可能会增加代码的复杂性。
- 性能开销:在桥接模式中,抽象类和具体实现类之间的调用可能引入性能开销。
- 过度设计:在某些情况下,桥接模式可能被过度使用,导致不必要的复杂性。
- 多重继承的替代方案:在某些语言中,多重继承可以提供与桥接模式类似的功能,但可能更简单且性能更高。
- 接口的稳定性:桥接模式依赖于稳定的抽象接口。如果接口经常更改,则可能会导致应用程序不稳定。
何时使用桥接模式:
- 当你需要在不改变抽象部分的情况下改变实现部分时。
- 当你想要将不同类型的实现封装在统一的接口后面时。
- 当你想在多个平台或环境中使用相同的抽象接口时。
何时不使用桥接模式:
- 当抽象部分和实现部分之间没有明确的分离时。
- 当性能开销不可接受时。
- 当代码的复杂性已经很高时。
5.最佳实践
桥接模式最佳实践:
- 明确分离抽象和实现:确保抽象接口只定义高级概念,而具体实现提供具体的实现细节。
- 保持抽象接口稳定:避免经常更改抽象接口,因为这可能会破坏依赖于该接口的代码。
- 使用组合而非继承:桥接模式通常使用组合而不是继承来实现分离,这提供了更大的灵活性。
- 避免过度使用:只有在确实需要在不更改抽象的情况下更改实现时才使用桥接模式。
- 考虑性能开销:在桥接模式中,抽象类和具体实现类之间的调用可能会引入性能开销,因此在性能关键的应用程序中要谨慎使用。
- 使用清晰的命名约定:为抽象接口、扩展抽象和具体实现类使用明确的命名约定,以提高代码的可读性和可维护性。
6.总结
桥接模式通过将抽象部分和实现部分分离,使得两者可以独立变化,能够做到抽象接口只定义高级概念,而具体实现提供具体的实现细节