介绍
桥接模式(Bridge Pattern)是一种结构型设计模式,它将抽象和实现解耦,使它们可以独立地变化。桥接模式通过将抽象部分与实现部分分离,使它们可以独立地进行扩展、修改和重用。
在桥接模式中,抽象部分和实现部分分别由两个独立的类层级结构组成。抽象部分包含高层级的抽象类或接口,定义了抽象的操作和业务逻辑。实现部分包含低层级的实现类或接口,提供了具体的实现细节。
桥接模式通过在抽象部分中包含对实现部分的引用,将抽象部分和实现部分连接起来。这种连接的方式使得抽象部分可以在运行时选择不同的实现部分,从而实现了两者的解耦。
主要设计的角色有:
- 抽象部分(Abstraction):定义抽象类或接口,它包含对实现部分的引用,并声明了一些抽象的操作。
- 具体抽象部分(Concrete Abstraction):实现抽象部分定义的抽象操作,通常包含一些具体的业务逻辑。
- 实现部分(Implementor):定义实现类或接口,提供了实现细节的接口。
- 具体实现部分(Concrete Implementor):实现实现部分的接口,提供具体的实现细节。
优点
- 抽象部分和实现部分解耦,互不影响。
- 可以轻松地扩展抽象部分和实现部分,而无需修改现有的代码。可以通过添加新的抽象部分或实现部分来增加新的功能,而不会影响到其他部分。
- 可以在运行时选择不同的实现部分,实现了抽象部分的可替代性。这使得系统更加灵活。
缺点
- 桥接模式需要定义抽象部分和实现部分的接口,并且需要进行适当的组合。这可能会增加一定的代码复杂性。
- 桥接模式涉及到多个类和接口的定义,可能会增加代码量。
使用场景
- 当你希望抽象部分和实现部分可以独立地变化和扩展时。
- 当你想要避免在抽象部分中使用继承来扩展功能时。
- 当你有多个抽象部分和多个实现部分,并且希望能够在运行时进行组合时。
比如:一个图形绘制系统可能有多种形状(如圆形、矩形)和多种绘制方式(如点阵、矢量)。使用桥接模式可以将形状和绘制方式解耦,使得每个形状都可以与任意一种绘制方式进行组合,从而灵活地绘制不同的图形。这样,如果需要新增一种形状或绘制方式,只需扩展相应的抽象部分和实现部分,而不需要修改已有的代码。
代码示例
package main
import "fmt"
// 定义实现接口 Shape,包含方法 NewShape
type Shape interface {
NewShape(x, y int) string
}
// 定义具体实现画圆 ShapeCircle
type ShapeCircle struct{}
// 实现方法
func NewShapeCircle() *ShapeCircle {
return &ShapeCircle{}
}
func (sc *ShapeCircle) NewShape(x, y int) string {
return fmt.Sprintf("画圆, x: %d, y: %d\n", x, y)
}
// 定义具体实现画矩形 ShapeRectangle
type ShapeRectangle struct{}
// 实现方法
func NewShapeRectangle() *ShapeRectangle {
return &ShapeRectangle{}
}
func (sr *ShapeRectangle) NewShape(x, y int) string {
return fmt.Sprintf("画矩形, x: %d, y: %d\n", x, y)
}
// 定义抽象画图接口,包含方法 Draw
type DrawShape interface {
Draw(x, y int)
}
// 定义具体抽象部分 NewDraw,使用 Shape 接口
type NewDraw struct {
sha Shape
}
// 实现方法
func (nd *NewDraw) Draw(x, y int) string {
return fmt.Sprintf("画图: %s", nd.sha.NewShape(x, y))
}
func main() {
// 使用具体实现 NewShapeCircle
nd := &NewDraw{sha: NewShapeCircle()}
// 使用抽象部分,引用具体实现
fmt.Println(nd.Draw(10, 10))
// 使用具体实现 NewShapeRectangle
nd = &NewDraw{sha: NewShapeRectangle()}
// 使用抽象部分,引用具体实现
fmt.Println(nd.Draw(20, 20))
}