设计模式-11 - Bridge Method 桥接模式

发布于:2024-05-17 ⋅ 阅读:(64) ⋅ 点赞:(0)
设计模式-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.总结


桥接模式通过将抽象部分和实现部分分离,使得两者可以独立变化,能够做到抽象接口只定义高级概念,而具体实现提供具体的实现细节