六、bridge 桥接模式
- 复杂逻辑拆分:
如果需要完成复杂的逻辑,可以把复杂逻辑设计为接口,内部再拆分为若干接口。这样复杂的逻辑会被拆分开,方便解耦。
例如:如果遥控器控制设备。可以遥控器设计为复杂接口,设备设计为简单接口。遥控器的每个方法都由若干设备接口组成。设备可以有多种实现:如电视、手机等。
- 多维,避免组合爆炸
如果有多个维度,各维度之间可以设计为接口,而不是让组合的数量爆炸。
例如:如果有 mac 和 windows 两种 os,需要分别连接 hp 和 epson 的打印机打印。为了避免实现 2x2 种组合类型(如 mac-hp、mac-epson、windows-hp、windows-epson 等),可以用接口。
6.1 多维:os 和 printer
目录层级如下:
06bridge/061osprinter
├── epson_printer.go
├── hp_printer.go
├── mac_os.go
├── os.go
├── os_test.go
├── printer.go
├── readme.md
└── windows_os.go
6.1.1 os.go
package _61osprinter
type os interface {
Print()
SetPrinter(p printer)
}
6.1.2 os_test.go
package _61osprinter
import (
"fmt"
"testing"
)
/*
=== RUN TestOsPrint
mac系统
hp打印机
mac系统
爱普生打印机
windows系统
hp打印机
windows系统
爱普生打印机
--- PASS: TestOsPrint (0.00s)
PASS
*/
func TestOsPrint(t *testing.T) {
hp := &hpPrinter{}
epson := &epsonPrinter{}
// mac
mac := &macOs{}
mac.SetPrinter(hp)
mac.Print()
fmt.Println()
mac.SetPrinter(epson)
mac.Print()
fmt.Println()
// win
win := &windowsOs{}
win.SetPrinter(hp)
win.Print()
fmt.Println()
win.SetPrinter(epson)
win.Print()
fmt.Println()
}
6.1.3 os.go
package _61osprinter
type os interface {
Print()
SetPrinter(p printer)
}
6.1.4 priner.go
package _61osprinter
type printer interface {
Print()
}
6.1.5 mac_os.go
package _61osprinter
import "fmt"
type macOs struct {
printer printer
}
func (o *macOs) Print() {
fmt.Println("mac系统")
o.printer.Print()
}
func (o *macOs) SetPrinter(p printer) {
o.printer = p
}
6.1.6 windows_os.go
package _61osprinter
import "fmt"
type windowsOs struct {
printer printer
}
func (o *windowsOs) Print() {
fmt.Println("windows系统")
o.printer.Print()
}
func (o *windowsOs) SetPrinter(p printer) {
o.printer = p
}
6.1.7 hp_printer.go
package _61osprinter
import "fmt"
type hpPrinter struct {
}
func (p *hpPrinter) Print() {
fmt.Println("hp打印机")
}
6.1.8 epson_printer.go
package _61osprinter
import "fmt"
type epsonPrinter struct{}
func (p *epsonPrinter) Print() {
fmt.Println("爱普生打印机")
}
6.2 client、remote、device
如果 client 希望控制 remote,remote 希望控制 device,device 可能有多种。可以将 remote 和 device 都抽象为接口。
06bridge/062client_remote_device
├── bluetooth_remote.go
├── device.go
├── infrared_remote.go
├── radio_device.go
├── readme.md
├── remote.go
├── remote_test.go
└── tv_device.go
6.2.1 remote_test.go
package _62client_remote_device
import "testing"
func TestTvRemote(t *testing.T) {
rs := []remote{
&infraredRemote{dev: &tvDevice{}},
&infraredRemote{dev: &radioDevice{}},
&bluetoothRemote{dev: &tvDevice{}},
&bluetoothRemote{dev: &radioDevice{}},
}
for _, r := range rs {
r.togglePower()
r.channelUp()
}
}
6.2.2 remote.go
package _62client_remote_device
type remote interface {
togglePower()
channelUp()
}
6.2.3 device.go
package _62client_remote_device
type device interface {
// 开关
isEnabled() bool
enable()
disable()
// 频道
getChannel() int
setChannel(c int)
}
6.2.4 infrared_remote.go
package _62client_remote_device
// 红外遥控器
type infraredRemote struct {
dev device
}
func (r *infraredRemote) togglePower() {
if r.dev.isEnabled() {
r.dev.disable()
} else {
r.dev.enable()
}
}
func (r *infraredRemote) channelUp() {
old := r.dev.getChannel()
r.dev.setChannel(old + 1)
}
6.2.5 bluetooth_remote.go
package _62client_remote_device
// 蓝牙遥控器
type bluetoothRemote struct {
dev device
}
func (r *bluetoothRemote) togglePower() {
if r.dev.isEnabled() {
r.dev.disable()
} else {
r.dev.enable()
}
}
func (r *bluetoothRemote) channelUp() {
old := r.dev.getChannel()
r.dev.setChannel(old + 1)
}
6.2.6 tv_device.go
package _62client_remote_device
type tvDevice struct {
// 开关
enabled bool
// 频道
channel int
}
func (d *tvDevice) isEnabled() bool {
return d.enabled
}
func (d *tvDevice) enable() {
d.enabled = true
}
func (d *tvDevice) disable() {
d.enabled = false
}
func (d *tvDevice) getChannel() int {
return d.channel
}
func (d *tvDevice) setChannel(c int) {
d.channel = c
}
6.2.7 radio_device.go
package _62client_remote_device
type radioDevice struct {
enabled bool
channel int
}
func (d *radioDevice) isEnabled() bool {
return d.enabled
}
func (d *radioDevice) enable() {
d.enabled = true
}
func (d *radioDevice) disable() {
d.enabled = false
}
func (d *radioDevice) getChannel() int {
return d.channel
}
func (d *radioDevice) setChannel(c int) {
d.channel = c
}
6.3 notifier_sender
需要实现一个通知发送器, 有如下两个维度:
- 生产消息: 根据内容, 生产消息
- 触达用户: 利用网络, 发消息给用户
这其实是两个步骤, 可以拆分开, 使解耦.
06bridge/063notifier_sender
├── notifier.go
├── notifier_test.go
├── readme.md
└── sender.go
6.3.1 notifier_test.go
package _63notifier_sender
import "testing"
/*
=== RUN TestNotify
广告通知
通过微信发送
广告通知
通过飞书发送
广告通知
通过电话发送
欢迎通知
通过微信发送
欢迎通知
通过飞书发送
欢迎通知
通过电话发送
--- PASS: TestNotify (0.00s)
PASS
*/
func TestNotify(t *testing.T) {
ns := []Notifier{
&AdvertisementNotifier{sender: &WechatSender{}},
&AdvertisementNotifier{sender: &LarkSender{}},
&AdvertisementNotifier{sender: &PhoneSender{}},
&GreetingNotifier{&WechatSender{}},
&GreetingNotifier{&LarkSender{}},
&GreetingNotifier{&PhoneSender{}},
}
for _, n := range ns {
n.Notify()
}
}
6.3.2 notifier.go
package _63notifier_sender
import "fmt"
// Notifier 通知者
type Notifier interface {
Notify()
}
type AdvertisementNotifier struct {
sender Sender
}
func (n *AdvertisementNotifier) Notify() {
fmt.Println("广告通知")
n.sender.Send()
}
type GreetingNotifier struct {
Sender
}
func (n *GreetingNotifier) Notify() {
fmt.Println("欢迎通知")
n.Send()
}
6.3.3 sender.go
package _63notifier_sender
import (
"fmt"
)
type Sender interface {
Send()
}
type WechatSender struct {
}
func (s *WechatSender) Send() {
fmt.Println("通过微信发送")
}
type LarkSender struct {
}
func (s *LarkSender) Send() {
fmt.Println("通过飞书发送")
}
type PhoneSender struct{}
func (s *PhoneSender) Send() {
fmt.Println("通过电话发送")
}