橋接模式

<image>

橋接模式（bridge pattern），是一種軟體設計模式，它將針對事物的抽象與其實現進行解耦，使它們可以各自獨立的變化。橋接使用了封裝、對象合成#聚集和繼承來將諸多責任分離進入不同的類之中。

## 結構

<image>

。

在上面的UML類圖中，抽象類（`Abstraction`）不實現為平常的單一繼承層級。這裡轉而有個層級用於抽象類（`Abstraction`），另一個獨立的層級用於它的實現者（`Implementor`），這使得二者相互獨立。`Abstraction`接口（`operation()`）的實現依據了（委託於）`Implementor`接口（`imp.operationImp()`）。

UML序列圖展示了運行時交互：`Abstraction1`對象委託實現於`Implementor1`對象（通過調用`operationImp()`在`Implementor1`之上），它進行運算並返回到`Abstraction1`。

### 參與者

- Abstraction：定義抽象的介面。該介面包含實現具體行爲、具體特徵的Implementor介面。
- Refined Abstraction：抽象介面Abstraction的子類，依舊是一個抽象的事物名。
- Implementor：定義具體行爲、具體特徵的應用介面。
- ConcreteImplementor：實現Implementor介面。

## 示例

橋接模式將事物對象的抽象概念與其具體行爲和特徵分離開來，如「圓形」、「三角形」歸於抽象的「形狀」之下，而「畫圓」、「畫三角」歸於實現行爲的「畫圖」類之下，然後將事物對象的抽象概念與其行爲橋接起來，即由「形狀」調用「畫圖」，例如：「圓形」調用「畫圓」，而「三角形」調用「畫三角」。下列各語言的代碼都用於寫出兩個不同的圓的坐標和半徑。

### C++

下面是C++的例子：

```cpp
import std;

using std::string;
using std::vector;

class DrawingAPI {
public:
    virtual ~DrawingAPI() = default;
    virtual string drawCircle(float x, float y, float radius) const = 0;
};

class DrawingAPI01: public DrawingAPI {
public:
    [[nodiscard]]
    string drawCircle(float x, float y, float radius) const override {
        return std::format("API01.circle at {}:{} - radius: {}", x, y, radius); 
    }
};

class DrawingAPI02: public DrawingAPI {
public:
    [[nodiscard]]
    string drawCircle(float x, float y, float radius) const override {
        return std::format("API02.circle at {}:{} - radius: {}", x, y, radius);
    }
};

class Shape {
protected:
    const DrawingAPI& drawingApi;
public:
    Shape(const DrawingAPI& api):
        drawingApi{api} {}

    virtual ~Shape() = default;

    virtual string draw() const = 0;
    virtual float resizeByPercentage(const float percent) noexcept = 0;
};

class CircleShape: public Shape {
private:
    float x;
    float y;
    float radius;
public:    
    CircleShape(const DrawingAPI& api, float x, float y, float radius): 
        Shape(api), x{x}, y{y}, radius{radius} {}

    [[nodiscard]]
    string draw() const override {
        return api.drawCircle(x, y, radius);
    }

    [[nodiscard]]
    float resizeByPercentage(float percent) noexcept override {
        return radius *= (1.0f + percent / 100.0f);
    }
};

int main(int argc, char* argv[]) {
    const DrawingAPI01 api1;
    const DrawingAPI02 api2;
    vector<CircleShape> shapes { 
        CircleShape{1.0f, 2.0f, 3.0f, api1}, 
        CircleShape{5.0f, 7.0f, 11.0f, api2} 
    }; 

    for (CircleShape& shape: shapes) {
        shape.resizeByPercentage(2.5);
        std::println("{}", shape.draw());
    }

    return 0;
}
```

輸出為:

```output
API01.circle at 1.000000:2.000000 - radius: 3.075000
API02.circle at 5.000000:7.000000 - radius: 11.275000
```

### Java

下面是Java的例子：

```java
/** "Implementor" */
interface DrawingAPI {
     public void drawCircle(double x, double y, double radius);
}

/** "ConcreteImplementor" 1/2 */
class DrawingAPI1 implements DrawingAPI {
     public void drawCircle(double x, double y, double radius) {
         System.out.printf("API1.circle at %f:%f radius %f\n", x, y, radius);
    }
}

/** "ConcreteImplementor" 2/2 */
class DrawingAPI2 implements DrawingAPI {
    public void drawCircle(double x, double y, double radius) { 
        System.out.printf("API2.circle at %f:%f radius %f\n", x, y, radius);
    }
}

/** "Abstraction" */
interface Shape {
    public void draw();                             // low-level
    public void resizeByPercentage(double pct);     // high-level
}

/** "Refined Abstraction" */
class CircleShape implements Shape {
    private double x, y, radius;
    private DrawingAPI drawingAPI;
    public CircleShape(double x, double y, double radius, DrawingAPI drawingAPI) {
        this.x = x;  this.y = y;  this.radius = radius; 
        this.drawingAPI = drawingAPI;
    }

    // low-level i.e. Implementation specific
    public void draw() {
        drawingAPI.drawCircle(x, y, radius);
    }   
    // high-level i.e. Abstraction specific
    public void resizeByPercentage(double pct) {
        radius *= pct;
    }
}

/** "Client" */
class BridgePattern {
    public static void main(String[] args) {
        Shape[] shapes = new Shape[2];
        shapes[0] = new CircleShape(1, 2, 3, new DrawingAPI1());
        shapes[1] = new CircleShape(5, 7, 11, new DrawingAPI2());

        for (Shape shape : shapes) {
            shape.resizeByPercentage(2.5);
            shape.draw();
        }
    }
}
```

### C#

在下面的C#例子中，泛型形式的`CircleShape<T>`，通過`T`來接受接口`IDrawingAPI`的`struct`形式的繼承者。

```csharp
using System;
 
/** "Implementor" */
interface IDrawingAPI {
    void DrawCircle(double x, double y, double radius);
}
 
/** "ConcreteImplementor" 1/2 */
struct DrawingAPI1 : IDrawingAPI {
    public void DrawCircle(double x, double y, double radius) {
        System.Console.WriteLine("API1.circle at {0}:{1} radius {2}", x, y, radius); 
    }
}
 
/** "ConcreteImplementor" 2/2 */
struct DrawingAPI2 : IDrawingAPI {
    public void DrawCircle(double x, double y, double radius) { 
        System.Console.WriteLine("API2.circle at {0}:{1} radius {2}", x, y, radius); 
    }
}
 
 /** "Abstraction" */
interface IShape {
    void Draw();                             // low-level (i.e. Implementation-specific)
    void ResizeByPercentage(double pct);     // high-level (i.e. Abstraction-specific)
}
 
/** "Refined Abstraction" */
class CircleShape<T> : IShape
    where T : struct, IDrawingAPI {
    private double x, y, radius;
    private static IDrawingAPI drawingAPI = new T();
    public CircleShape(double x, double y, double radius) {
        this.x = x;  this.y = y;  this.radius = radius;
    }
    // low-level (i.e. Implementation-specific)
    public void Draw() { drawingAPI.DrawCircle(x, y, radius); }
    // high-level (i.e. Abstraction-specific)
    public void ResizeByPercentage(double pct) { radius *= pct; }
}
 
/** "Client" */
class BridgePattern {
    public static void Main(string[] args) {
        IShape[] shapes = new IShape[2];
        shapes[0] = new CircleShape<DrawingAPI1>(1, 2, 3);
        shapes[1] = new CircleShape<DrawingAPI2>(5, 7, 11);
 
        foreach (IShape shape in shapes) {
            shape.ResizeByPercentage(2.5);
            shape.Draw();
        }
    }
}
```

### Python

在《設計模式》書中所舉的示例是設計部件工具箱，就像GTK與GDK之間的關係那樣，關於部件的抽象`Abstraction`及其具體化，與關於圖形庫的實現者接口`Implementor`及其跨越既有第三方平台（比如X11、Wayland、Quartz和GDI）的不同具體實現，二者中實現者接口`Implementor`是先決條件，根據它才能制定抽象`Abstraction`的特性和方法，並編寫不同的具體實現來適配不同的平台。

下面是Python的具有繪製為主要功能的圖形類層級例子，這裡的抽象`Abstraction`所具有的特性和方法是先決條件，接著根據它來制定其繪圖功能的實現者接口`Implementor`，並編寫不同的具體實現者比如柵格圖繪製和矢量圖繪製：

```python
from abc import ABCMeta, abstractmethod

class Shape(metaclass=ABCMeta):
    def __init__(self, impl_class):
        self.draw_impl = impl_class.draw
    def draw(self, *args, **kwargs):
        self.draw_impl(self, *args, **kwargs)
    @abstractmethod
    def resize_by_percentage(self): pass

class Circle(Shape):
    def __call__(self, x, y, radius):
        self.x = x
        self.y = y
        self.radius = radius
        return self
    def resize_by_percentage(self, percent):
        self.radius *= 1 + percent/100

class Drawing(metaclass=ABCMeta):
    @abstractmethod
    def draw(self): pass

class DrawingCircle1(Drawing):
    def draw(self):
        print("Implementor1: drawing a circle with a center at "
            + f"({self.x},{self.y}) and a radius of {self.radius}")
of
class DrawingCircle2(Drawing):
    def draw(self):
        print("Implementor2: drawing a circle with a center at "
            + f"({self.x},{self.y}) and a radius of {self.radius}")

def test():
    shape_list = [
        Circle(DrawingCircle1)(1.0, 2.0, 3.0),
        Circle(DrawingCircle2)(5.0, 7.0, 11.0)]
    for shape in shape_list:
        shape.resize_by_percentage(25)
        shape.draw()
```

這裡的`self.draw_impl(self)`，通過顯式的將圖形實例對象自身`this (计算机编程)`，傳遞給實現者類的函數`impl_class.draw(self)`作為其第一個實際參數，具體圖形對象在運行時自主選擇其繪圖功能的具體實現者。下面是其執行：

```pycon
>>> test()
Implementor1: drawing a circle with a center at (1.0,2.0) and a radius of 3.75
Implementor2: drawing a circle with a center at (5.0,7.0) and a radius of 13.75
```