桥接模式是结构型设计模式
GoF定义:将抽象部分与它的实现部分分离,使它们都可以独立地变化。
优点:用组合/聚合的方式来共享一些能用的方法 。
这个模式非常像网卡的桥接模式,把两个不同的局域网通过网卡连接起来。
简单示例
先看一个简单的示例:
go
package main
import"fmt"
type Implementor interface {
OperationImp()
}
type ConcreteImplementorA struct{}
func NewConcreteImplementorA() *ConcreteImplementorA {
return &ConcreteImplementorA{}
}
func (c *ConcreteImplementorA) OperationImp() {
fmt.Println("具体实现A")
}
type ConcreteImplementorB struct{}
func NewConcreteImplementorB() *ConcreteImplementorB {
return &ConcreteImplementorB{}
}
func (c *ConcreteImplementorB) OperationImp() {
fmt.Println("具体实现A")
}
type RefinedAbstraction struct {
Imp Implementor
}
func NewRefinedAbstraction() *RefinedAbstraction {
return &RefinedAbstraction{}
}
func (r *RefinedAbstraction) Operation() {
r.Imp.OperationImp()
}
func (r *RefinedAbstraction) SetImplementor(imp Implementor) {
r.Imp = imp
}
func main() {
implementorA := NewConcreteImplementorA()
implementorB := NewConcreteImplementorB()
refinedAbstraction := NewRefinedAbstraction()
refinedAbstraction.SetImplementor(implementorA)
refinedAbstraction.Operation()
refinedAbstraction.SetImplementor(implementorB)
refinedAbstraction.Operation()
}
上述这段代码,可以很容易理解。
SetImplementor(implementorA)
和 SetImplementor(implementorB)
可以动态的切换 Operation()
的实现,也就是把 Operation()
进行了抽象 。
实际案例
场景
会员系统,需要在用户订阅到货通知后,引导用户关注公众号,具体要求如下:
1.PC端:订阅了商品到货通知后,判断用户是否关注了公众号,没关注,需要展示公众号的二维码;已关注,不用展示。
2.微信小程序客户端:订阅了商品到货通知后,判断用户是否关注了公众号,没关注,需打开微信公众号文章,文章中会展示出 公众号的二维码,用户可以长按进行关注;已关注,不用展示。
3.手机浏览器H5客户端:订阅了商品到货通知后,不需要判断是否关注公众号。
对于不同端进行不同的操作,可以把这部分进行抽象。通过调用方法进行切换。
定义接口
go
type ISubscribe interface {
Subscribe(agent, productName string)
}
按照不同的客户端进行 Subscribe
方法的定制
PC端
go
type PCAlertStockSubscribe struct{}
func NewPCAlertStockSubscribe() ISubscribe {
return &PCAlertStockSubscribe{}
}
func (p *PCAlertStockSubscribe) Subscribe(agent, productName string) {
fmt.Println("记录到货知订阅")
fmt.Printf("客户端: %v, 商品: %v, 到货通知订阅成功\n", agent, productName)
fmt.Println("判断是否需引导用户关注公众号")
fmt.Println("获取微信公众号的二维码")
fmt.Println("引导用户关注公众号,展示微信公众号二维码")
}
微信小程序端
go
type MiniProgramAlertStockSubscribe struct{}
func NewMiniProgramAlertStockSubscribe() ISubscribe {
return &MiniProgramAlertStockSubscribe{}
}
func (m *MiniProgramAlertStockSubscribe) Subscribe(agent, productName string) {
fmt.Println("记录到货知订阅")
fmt.Printf("客户端: %v, 商品: %v, 到货通知订阅成功\n", agent, productName)
fmt.Println("判断是否需引导用户关注公众号")
fmt.Println("获取微信公众号的文章的连接")
fmt.Println("引导用户关注公众号,打开微信公众号文章,可以长按二维码进行关注")
}
手机浏览器H5端
go
type MobileAlertStockSubscribe struct{}
func NewMobileAlertStockSubscribe() ISubscribe {
return &MobileAlertStockSubscribe{}
}
func (m *MobileAlertStockSubscribe) Subscribe(agent, productName string) {
fmt.Println("记录到货知订阅")
fmt.Printf("客户端: %v, 商品: %v, 到货通知订阅成功\n", agent, productName)
}
通过 ProductAlertStockSubscribe
进行切换
go
type IProductSubscribe interface {
SetImpSubscribe(imp ISubscribe)
ExecSubscribe(agent, productName string)
}
type ProductAlertStockSubscribe struct {
Imp ISubscribe
}
func NewProductAlertStockSubscribe() IProductSubscribe {
return &ProductAlertStockSubscribe{}
}
func (p *ProductAlertStockSubscribe) SetImpSubscribe(imp ISubscribe) {
p.Imp = imp
}
func (p *ProductAlertStockSubscribe) ExecSubscribe(agent, productName string) {
p.Imp.Subscribe(agent, productName)
}
ProductAlertStockSubscribe
就可以类比网卡,调用 SetImpSubscribe
方法 ,让不同端的逻辑进行切换。
还需要定义一个映射关系,用于切换的客户端,这部分其实是策略模式。
go
type clientSubscribeFunc func() ISubscribe
const (
WebAgent = "web"
WapAgent = "wap"
MiniProgramAgent = "miniProgram"
)
var clientAlertStockSubscribeMap = map[string]clientSubscribeFunc{
WebAgent: NewPCAlertStockSubscribe,
MiniProgramAgent: NewMiniProgramAlertStockSubscribe,
WapAgent: NewMobileAlertStockSubscribe,
}
按照不同的客户端进行调用
go
func main() {
productName := "【设计模式:可复用面向对象软件的基础】"
productAlertStockSubscribe := NewProductAlertStockSubscribe()
agents := []string{WebAgent, MiniProgramAgent, WapAgent}
for _, agent := range agents {
// 策略模式的体现
alertStockSubscribeFunc := clientAlertStockSubscribeMap[agent]
alertStockSubscribe := alertStockSubscribeFunc()
// 桥接模式
productAlertStockSubscribe.SetImpSubscribe(alertStockSubscribe)
productAlertStockSubscribe.ExecSubscribe(agent, productName)
fmt.Println()
}
}
完整代码如下:
go
package main
import "fmt"
type ISubscribe interface {
Subscribe(agent, productName string)
}
type PCAlertStockSubscribe struct{}
func NewPCAlertStockSubscribe() ISubscribe {
return &PCAlertStockSubscribe{}
}
func (p *PCAlertStockSubscribe) Subscribe(agent, productName string) {
fmt.Println("记录到货知订阅")
fmt.Printf("客户端: %v, 商品: %v, 到货通知订阅成功\n", agent, productName)
fmt.Println("判断是否需引导用户关注公众号")
fmt.Println("获取微信公众号的二维码")
fmt.Println("引导用户关注公众号,展示微信公众号二维码")
}
type MiniProgramAlertStockSubscribe struct{}
func NewMiniProgramAlertStockSubscribe() ISubscribe {
return &MiniProgramAlertStockSubscribe{}
}
func (m *MiniProgramAlertStockSubscribe) Subscribe(agent, productName string) {
fmt.Println("记录到货知订阅")
fmt.Printf("客户端: %v, 商品: %v, 到货通知订阅成功\n", agent, productName)
fmt.Println("判断是否需引导用户关注公众号")
fmt.Println("获取微信公众号的文章的连接")
fmt.Println("引导用户关注公众号,打开微信公众号文章,可以长按二维码进行关注")
}
type MobileAlertStockSubscribe struct{}
func NewMobileAlertStockSubscribe() ISubscribe {
return &MobileAlertStockSubscribe{}
}
func (m *MobileAlertStockSubscribe) Subscribe(agent, productName string) {
fmt.Println("记录到货知订阅")
fmt.Printf("客户端: %v, 商品: %v, 到货通知订阅成功\n", agent, productName)
}
type IProductSubscribe interface {
SetImpSubscribe(imp ISubscribe)
ExecSubscribe(agent, productName string)
}
type ProductAlertStockSubscribe struct {
Imp ISubscribe
}
func NewProductAlertStockSubscribe() IProductSubscribe {
return &ProductAlertStockSubscribe{}
}
func (p *ProductAlertStockSubscribe) SetImpSubscribe(imp ISubscribe) {
p.Imp = imp
}
func (p *ProductAlertStockSubscribe) ExecSubscribe(agent, productName string) {
p.Imp.Subscribe(agent, productName)
}
type clientSubscribeFunc func() ISubscribe
const (
WebAgent = "web"
WapAgent = "wap"
MiniProgramAgent = "miniProgram"
)
var clientAlertStockSubscribeMap = map[string]clientSubscribeFunc{
WebAgent: NewPCAlertStockSubscribe,
MiniProgramAgent: NewMiniProgramAlertStockSubscribe,
WapAgent: NewMobileAlertStockSubscribe,
}
func main() {
productName := "【设计模式:可复用面向对象软件的基础】"
productAlertStockSubscribe := NewProductAlertStockSubscribe()
agents := []string{WebAgent, MiniProgramAgent, WapAgent}
for _, agent := range agents {
// 策略模式的体现
alertStockSubscribeFunc := clientAlertStockSubscribeMap[agent]
alertStockSubscribe := alertStockSubscribeFunc()
// 桥接模式
productAlertStockSubscribe.SetImpSubscribe(alertStockSubscribe)
productAlertStockSubscribe.ExecSubscribe(agent, productName)
fmt.Println()
}
}
总结
怎么样?是不是觉得很熟悉,是不是感觉已经使用过了,只是不知道这个是桥接模式。
体现了对扩展开放、修改关闭 设计原则
后续再次遇到这样类似的,我想你应该知道该怎么做了。