跳到主要内容

桥接模式

简介

桥接模式(Bridge Pattern)是将实现类封装在接口或抽象类内部的设计模式。桥接模式将抽象部分与实现部分分离,使它们可以独立变化。它是用组合关系替代继承关系实现的,可以降低抽象部分和实现部分这两个可变维度的耦合度。

角色组成:

  • Abstraction (抽象类): 定义抽象类的接口,并维护一个指向实现者(Implementor)对象的引用。它通常包含一些基本的业务逻辑,并将具体实现的操作委托给 Implementor 对象。
  • RefinedAbstraction (具体抽象类/扩展抽象类): 继承自 Abstraction,扩展由 Abstraction 定义的接口,实现更具体的业务逻辑。
  • Implementor (实现者接口): 定义实现类的接口,该接口不一定要与 Abstraction 的接口完全一致。通常它只提供基本操作,而 Abstraction 则基于这些基本操作定义更高层次的操作。
  • ConcreteImplementor (具体实现者类): 实现 Implementor 接口,给出具体的实现。

常见使用场景

  • 当你不希望抽象和它的实现部分之间有一个固定的绑定关系时。 例如,你希望在程序运行时动态地选择或切换实现。
  • 当抽象及其实现都可通过子类化独立进行扩展时。 桥接模式允许你组合不同的抽象和实现,并且可以独立地增加新的抽象或新的实现,而无需修改现有代码。
  • 当一个类的实现需要在运行时进行选择或切换时。
  • 当一个类存在多个维度的变化,并且希望避免类数量的指数级增长时。 比如,图形界面库需要在不同操作系统(Windows、macOS、Linux)上绘制不同的窗口控件(按钮、文本框)。使用桥接模式,可以将“窗口控件”作为抽象,将“操作系统绘制API”作为实现,避免创建 WindowsButton, MacButton, LinuxButton, WindowsTextBox, MacTextBox, LinuxTextBox 等大量的类。
  • 需要在多个对象间共享实现(可能使用引用计数),并且对客户端隐藏该实现细节时。

优点

  • 分离抽象和实现: 这是最核心的优点,使得抽象和实现可以独立演化,互不影响。
  • 提高可扩展性: 抽象和实现可以各自独立地扩展,符合开闭原则。增加新的抽象类或实现类都相对容易。
  • 客户端代码更简洁: 客户端只需要与抽象类交互,无需关心具体的实现细节。
  • 更好的灵活性: 可以在运行时动态地切换实现部分。
  • 隐藏实现细节: 客户端看不到具体的实现,只依赖于抽象接口。

缺点

  • 增加系统复杂度: 引入了额外的类(Implementor 接口和其实现类),使得系统的结构变复杂,理解成本有所增加。
  • 设计难度: 需要在设计初期就准确地识别出合适的抽象和实现维度,并进行分离。如果设计不当,可能达不到预期效果。
  • 可能存在一定的性能影响: 由于增加了一层间接调用(抽象委托给实现),可能会带来微小的性能损失(通常可忽略不计)。

示例代码

Simple

Python

from abc import ABCMeta, abstractmethod


class Implementor(metaclass=ABCMeta):
@abstractmethod
def implementation(self):
pass

class ConcreteImplementor(Implementor):
def implementation(self, s: str):
print(f"ConcreteImplementor: {s}")

class RefineAbstraction:
def __init__(self, i: Implementor):
self.method = i

def execute(self, s: str):
self.method.implementation(s)

if __name__ == "__main__":
c = ConcreteImplementor()
r = RefineAbstraction(c)
r.execute("Hello World!")

Go

package bridge

import "fmt"

type Implementor interface {
Implementation(str string)
}

type ConcreteImplementor struct{}

func (*ConcreteImplementor) Implementation(str string) {
fmt.Printf("Implementation: %s\n", str)
}

func NewConcreteImplementor() *ConcreteImplementor {
return &ConcreteImplementor{}
}

type RefinedAbstraction struct {
method Implementor
}

func (c *RefinedAbstraction) Execute(str string) {
c.method.Implementation(str)
}

func NewRefinedAbstraction(im Implementor) *RefinedAbstraction {
return &RefinedAbstraction{method: im}
}

client

package bridge

import "testing"

func TestSimple(t *testing.T) {
c := NewConcreteImplementor()
r := NewRefinedAbstraction(c)
r.Execute("Hello World!")
}

电脑打印机

Python

from abc import ABC, abstractmethod

class Computer(ABC):
@abstractmethod
def print_(self):
pass

@abstractmethod
def set_printer(self, printer):
pass

class Printer(ABC):
@abstractmethod
def print_file(self):
pass

class Mac(Computer):
def __init__(self, printer: Printer):
self.printer = printer

def print_(self):
print("Mac Print")
self.printer.print_file()

def set_printer(self, printer: Printer):
self.printer = printer

class Lenovo(Computer):
def __init__(self, printer: Printer):
self.printer = printer

def print_(self):
print("Lenovo Print")
self.printer.print_file()

def set_printer(self, printer: Printer):
self.printer = printer

class Canon(Printer):
def print_file(self):
print("Printing by a Canon Printer")

class Hp(Printer):
def print_file(self):
print("Printing by a Hp Printer")

# 示例用法
if __name__ == "__main__":
canon_printer = Canon()
hp_printer = Hp()

mac = Mac(canon_printer)
mac.print_() # 输出: Mac Print
# Printing by a Canon Printer

mac.set_printer(hp_printer)
mac.print_() # 输出: Mac Print
# Printing by a Hp Printer

lenovo = Lenovo(hp_printer)
lenovo.print_() # 输出: Lenovo Print
# Printing by a Hp Printer

Go

package bridge

import "fmt"

type Computer interface {
Print()
SetPrinter(Printer)
}

type Printer interface {
PrintFile()
}

type Mac struct {
Printer Printer
}

func (m *Mac) Print() {
fmt.Println("Mac Print")
m.Printer.PrintFile()
}

func (m *Mac) SetPrinter(p Printer) {
m.Printer = p
}

type Lenovo struct {
Printer Printer
}

func (l *Lenovo) Print() {
fmt.Println("Lenovo Print")
l.Printer.PrintFile()
}

func (l *Lenovo) SetPrinter(p Printer) {
l.Printer = p
}


type Canon struct {}

func (c *Canon) PrintFile() {
fmt.Println("Printing by a Canon Printer")
}

type Hp struct {}

func (h *Hp) PrintFile() {
fmt.Println("Printing by a Hp Printer")
}

client

package bridge

import (
"testing"
)

func TestComputer(t *testing.T) {
hpPrinter := &Hp{}
canonPrinter := &Canon{}

mac := &Mac{Printer: hpPrinter}
mac.Print()
mac.SetPrinter(canonPrinter)
mac.Print()

lenovo := &Lenovo{Printer: canonPrinter}
lenovo.Print()
lenovo.SetPrinter(hpPrinter)
lenovo.Print()
}