轻松理解 Golang 桥接模式

用途

利用接口将不同种类的对象灵活的组装在一起。

实战

假设我们现在有 Mac 和 Windows 两种类型计算机,同时又有 epon 和 hp 两种打印机。那么我们如何将计算机与打印机这两种对象结合在一起呢?

有人说好办:创建 MacWithEpon、MacWithHp、WindowsWithEpon、WindowsWithHp 四个对象。这种实现方式很挫,比如现在又来了一批投影仪该咋办呢?

这时候我们可以利用桥接模式来解决问题,首先我们将计算机和打印机抽象成 Computer接口和 Printer 接口,Mac、Windows、Epon、Hp 分别是这些接口的实现。我们需要做的是将接口进行组合同时保证有能力替换接口的实现类image.png

代码实现

示例代码已经上传到我的 Github: https://github.com/kaolengmian7/golang-demo/tree/master/design_pattern/bridge 计算机 domain:

type computer interface {
	Run()
}

type mac struct {
	printer printer
}

func (m *mac) Run() {
	fmt.Println("mac run")
}

type windows struct {
	printer printer
}

func (w *windows) Run() {
	fmt.Println("windows run")
}

打印机 domain:

type printer interface {
	PrintFile()
}

type epson struct{}

func (p *epson) PrintFile() {
	fmt.Println("Printing by a EPSON printer")
}

type hp struct{}

func (p *hp) PrintFile() {
	fmt.Println("Printing by a HP printer")
}

跑一下测试:

func TestBridge(t *testing.T) {

	hpPrinter := &hp{}
	epsonPrinter := &epson{}

	macComputer := &mac{}
	macComputer.printer = hpPrinter
	macComputer.printer.PrintFile()
	fmt.Println()

	macComputer.printer = epsonPrinter
	macComputer.printer.PrintFile()
	fmt.Println()

	winComputer := &windows{}
	winComputer.printer = hpPrinter
	winComputer.printer.PrintFile()
	fmt.Println()

	winComputer.printer = epsonPrinter
	winComputer.printer.PrintFile()
	fmt.Println()
}
-----------------输出---------------------
=== RUN   TestBridge
Printing by a HP printer

Printing by a EPSON printer

Printing by a HP printer

Printing by a EPSON printer

优点

以桥接模式来组织对象,类的组成非常灵活(对比继承的方式),类的数量和层级数量大大降低。

通过组合关系来替代继承关系,避免继承层次的指数级爆炸。

除此之外,因为各个类被解耦,所以类与类之间相对独立,这允许我们独立扩展/更改某个类。

现实应用

Java 中的数据库工具 JDBC 充分利用了桥接模式。 JDBC 可以通过一行代码更改数据库类型:如果我们想要把 MySQL 数据库换成 Oracle 数据库,只需要把第一行代码中的 com.mysql.jdbc.Driver 换成 oracle.jdbc.driver.OracleDriver

Class.forName("com.mysql.jdbc.Driver");	//加载及注册JDBC驱动程序
String url = "jdbc:mysql://localhost:3306/sample_db?user=root&password=your_password";
Connection con = DriverManager.getConnection(url);

Mysql、Oracle 等数据库驱动都实现了 Sql.driver 接口,DriverManager 负责管理 driver 的实现类,从而达成无缝替换数据库驱动的目标。 image.png

最后

桥接模式在教科书上的定义是:将抽象和实现解耦,让它们可以独立变化。相信到了这里,大家已经可以轻松理解这个定义。


参考:

  1. https://refactoringguru.cn/design-patterns/bridge
  2. https://time.geekbang.org/column/article/202786