热门问题
时间线
聊天
视角
橋接模式
来自维基百科,自由的百科全书
Remove ads
橋接模式(英語:bridge pattern),是一種軟體設計模式, 它將針對事物的抽象與其實現進行解耦,使它們可以各自獨立的變化。橋接使用了封裝、聚集和繼承來將諸多責任分離進入不同的類之中。

結構

、
在上面的UML類圖中,抽象類(Abstraction)不實現為平常的單一繼承層級。這裡轉而有個層級用於抽象類(Abstraction),另一個獨立的層級用於它的實現者(Implementor),這使得二者相互獨立。Abstraction接口(operation())的實現依據了(委託於)Implementor接口(imp.operationImp())。
UML序列圖展示了運行時交互:Abstraction1對象委託實現於Implementor1對象(通過調用operationImp()在Implementor1之上),它進行運算並返回到Abstraction1。
- Abstraction:定義抽象的介面。該介面包含實現具體行爲、具體特徵的Implementor介面。
- Refined Abstraction:抽象介面Abstraction的子類,依舊是一個抽象的事物名。
- Implementor:定義具體行爲、具體特徵的應用介面。
- ConcreteImplementor:實現Implementor介面。
示例
橋接模式將事物對象的抽象概念與其具體行爲和特徵分離開來,如「圓形」、「三角形」歸於抽象的「形狀」之下,而「畫圓」、「畫三角」歸於實現行爲的「畫圖」類之下,然後將事物對象的抽象概念與其行爲橋接起來,即由「形狀」調用「畫圖」,例如:「圓形」調用「畫圓」,而「三角形」調用「畫三角」。下列各語言的代碼都用於寫出兩個不同的圓的坐標和半徑。
下面是C++的例子:
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;
}
輸出為:
API01.circle at 1.000000:2.000000 - radius: 3.075000
API02.circle at 5.000000:7.000000 - radius: 11.275000
Remove ads
下面是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();
}
}
}
Remove ads
在下面的C#例子中,泛型形式的CircleShape<T>,通過T來接受接口IDrawingAPI的struct形式的繼承者。
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();
}
}
}
Remove ads
在《設計模式》書中所舉的示例是設計部件工具箱,就像GTK與GDK之間的關係那樣,關於部件的抽象Abstraction及其具體化,與關於圖形庫的實現者接口Implementor及其跨越既有第三方平台(比如X11、Wayland、Quartz和GDI)的不同具體實現,二者中實現者接口Implementor是先決條件,根據它才能制定抽象Abstraction的特性和方法,並編寫不同的具體實現來適配不同的平台。
下面是Python的具有繪製為主要功能的圖形類層級例子,這裡的抽象Abstraction所具有的特性和方法是先決條件,接著根據它來制定其繪圖功能的實現者接口Implementor,並編寫不同的具體實現者比如柵格圖繪製和矢量圖繪製,通過傳遞顯式的self參數,在運行時由具體圖形對象選擇其繪圖功能的具體實現者:
from abc import ABCMeta, abstractmethod
class Shape(metaclass=ABCMeta):
def __init__(self, implement):
self.draw_impl = implement.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 circle at "
+ f"({self.x},{self.y}) and radius={self.radius}")
class DrawingCircle2(Drawing):
def draw(self):
print("Implementor2: drawing circle at "
+ f"({self.x},{self.y}) and radius={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()
其執行:
>>> test()
Implementor1: drawing circle at (1.0,2.0) and radius=3.75
Implementor2: drawing circle at (5.0,7.0) and radius=13.75
Remove ads
引用
Wikiwand - on
Seamless Wikipedia browsing. On steroids.
Remove ads
