桥接模式是一种结构型设计模式,可将一个大类或一系列紧密相关的类拆分为抽象和实现两个独立的层次结构,从而能在开发时分别使用。
解决什么问题?
想象一下以下的场景,随着业务的扩展,需要将日志存储到redis,mysql,或发送到远程日志服务器,而不仅仅是存储到本地文件中。如果按照笨办法,将原先存储在本地文件的代码全部修改成存储到mysql中,不仅修改的地方多,而且容易出bug。以后修改存储方式也很麻烦。此时可以考虑使用桥接模式将存储日志的共同行为抽象成接口,供上层控制逻辑类调用(抽象),而具体的存储方式各自实现(实现)。上层控制逻辑类通过对接口的组合实现全新的功能。
实现步骤:
- 创建实体类接口,实体类各自实现接口
- 将控制逻辑类与具体的实体类关联(依赖注入)
- 控制逻辑类组合接口,形成新接口
- 客户端调用控制逻辑类,逻辑类调用具体的实现类,传播请求
优势:
- 你可以创建与平台无关的类和程序。
- 客户端代码仅与控制逻辑类(抽象)进行互动, 不会接触到具体实现类(实现)。
- 开闭原则。 你可以新增抽象部分和实现部分, 且它们之间不会相互影响。
- 单一职责原则。 抽象部分专注于处理高层逻辑, 实现部分处理平台细节。
劣势:
- 对高内聚的类使用该模式可能会让代码更加复杂。
下面是实现代码:
package main
type device interface {
enable()
disable()
getVolume() int32
setVolume(percent int32)
}
type radio struct{}
func (r *radio) enable() {}
func (r *radio) disable() {}
func (r *radio) getVolume() int32 { return 0 }
func (r *radio) setVolume(percent int32) {}
type remote struct {
d device
}
func (r *remote) togglePower(on bool) {
if on {
r.d.enable()
} else {
r.d.disable()
}
}
func (r *remote) volumeUp() {
r.d.setVolume(r.d.getVolume() + 1)
}
func (r *remote) volumeDown() {
r.d.setVolume(r.d.getVolume() - 1)
}
func newRemote(d device) *remote {
return &remote{
d: d,
}
}
func main() {
r := newRemote(&radio{})
r.togglePower(true)
r.volumeUp()
r.togglePower(false)
}