桥接模式#
桥接模式是一种结构型设计模式, 可将一个大类或一系列紧密相关的类拆分为抽象和实现两个独立的层次结构,从而使得二者很好的解耦并且能在开发时分别使用。又称为柄体(Handle and Body)模式或接口(Interface)模式。
问题引入#
现在存在有一个Shape
类,现在子类两个Square
和Circle
。
type struct Shape {}
type struct Square {
Shape
}
type struct Circle {
Shape
}
go现在当我们需要给每一个Shape
添加Color
颜色属性,包括Blue
, Red
。所以按照继承的思想,自然而然地就会衍生出BlueCircle
、BlueSquare
、RedCircle
、RedSquare
四个对应颜色和形状的子类。
照这样下去的话,当我们需要之后扩展这一整个程序时,Shape
假定有m个,Color
假定有n个,那么最终我们需要创建的子类就将高达m * n个。这显然不是一个办法。
所以为了将 m * n 转变为 m + n,桥接模式是最合适的
解决问题#
桥接模式就是为了解决多个独立维度的问题而存在的
桥接模式通过继承改为组合的方式来解决该问题。具体来说,就是抽取其中一个维度使其成为独立的类层次(Abstraction),这样就可以在初始类中引用这个新层次的对象,从而使得一个类不必拥有所有的状态和行为。
这样,我们可以将颜色相关的代码抽取为更高层次的一个Color
类,其中包含Blue
、Red
两个具体颜色的子类。之后我们在Shape
类中添加一个变量,该变量是一个指向某一颜色对象的引用变量,现在我们就可以把所有有关颜色的操作全都委派给该引用变量,这样这个引用就成为了Shape
和Color
之间的桥梁,之后在更改颜色的时候,就可以不再修改添加更多的类。
Abstraction & Implementation#
在Gang of Four
的著作中,他们提出了两个学术术语:Abstraction
和 Implementation
。分别代表抽象层和实现层。
Abstraction: “Abstraction defines the abstraction’s interface and maintains a reference to an object of type Implementor.”
Implementor: ““Implementor defines the interface for implementation classes. This interface doesn’t have to correspond exactly to Abstraction’s interface; in fact the two interfaces can be quite different. Typically the Implementor interface provides only primitive operations, and Abstraction defines higher-level operations based on these primitives.””
抽象层包含着更高一级的命令与操作,而具体实现层则是包含更加原子的操作,抽象层中命令是对具体实现层中的原子操作的综合调用。
这在设计系统的时候可见一斑。
在实际设计系统的时候,抽象部分可以是GUI,而实现部分则是底层操作系统的API。任何一次鼠标的点击,键盘的敲击,都是通过调用实现部分来给予用户响应的。
我们可以从两个独立的方向扩展应用:
- GUI 支持不同的用户权限的GUI画面
- API 支持更多操作系统 (MACOS、Linux、Windows)
抽象对象控制程序的外观, 并将真实工作委派给连入的实现对象。 不同的实现只要遵循相同的接口就可以互换, 使同一 GUI 可在 Windows 和 Linux 下运行。
桥接模式整体结构#
具体实现#
现在我们有两台不同的打印机(HP Epson)以及两台不同操作系统的电脑(Mac Linux),我们不会关系具体电脑调用打印机进行打印的细节。而是通过抽象层(电脑)实施层(打印机)来实现两个独立维度的解耦。
type Computer interface {
Print()
// 设置引用另一位维度的对象
SetPrinter(Printer)
}
type Mac struct {
printer Printer
}
func (m *Mac) Print() {
fmt.Println("Print request for mac")
m.printer.PrintFile()
}
func (m *Mac) SetPrinter(p Printer) {
m.printer = p
}
type Linux struct {
printer Printer
}
func (w Linux) Print() {
fmt.Println("Print request for Linux")
w.printer.PrintFile()
}
func (w Linux) SetPrinter(p Printer) {
w.printer = p
}
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")
}
go