

手撸golang 行为型设计模式 中介者模式
source link: https://studygolang.com/articles/33292
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

手撸golang 行为型设计模式 中介者模式
缘起
最近复习设计模式
拜读谭勇德的<<设计模式就该这样学>>
本系列笔记拟采用golang练习之
中介者模式
中介者模式(Mediator Pattern)又叫作调解者模式或调停者模式。 用一个中介对象封装一系列对象交互, 中介者使各对象不需要显式地相互作用, 从而使其耦合松散, 而且可以独立地改变它们之间的交互, 属于行为型设计模式。 中介者模式主要适用于以下应用场景。 (1)系统中对象之间存在复杂的引用关系,产生的相互依赖关系结构混乱且难以理解。 (2)交互的公共行为,如果需要改变行为,则可以增加新的中介者类。 (摘自 谭勇德 <<设计模式就该这样学>>)
场景
- 某物联网企业, 研发各种智能家居产品, 并配套手机app以便用户集中控制
- 一开始的设计是手机app通过本地局域网的广播协议, 主动发现/注册/控制各种智能设备
- 后来智能设备的种类越来越多, 通信协议多种多样, 导致手机app需要频繁升级, 集成过多驱动导致代码膨胀
- 研发部门痛定思痛, 决定采用 中介者模式 重新设计整个系统架构
- 老架构: app -> 智能设备*N
- 新架构: app -> 云中心 -> 智能设备
- 通过引入"云中心" 作为中介, 将app与设备驱动解耦
- app与云中心采用RESTFul协议通信, 极大提升开发运维的效率
设计
- MockPhoneApp: 虚拟的手机app, 用于跟云中心通信, 控制智能设备
- ICloudMediator: 云中心面向手机app的接口
- ICloudCenter: 云中心面向智能设备的注册接口
- ISmartDevice: 智能设备接口
- tMockCloudMediator: 虚拟的云中心服务类, 面向手机app实现ICloudMediator接口, 面向智能设备实现ICloudCenter接口
- tMockSmartLight: 虚拟的智能灯设备, 实现ISmartDevice接口
单元测试
mediator_pattern_test.go
package behavioral_patterns import ( "learning/gooop/behavioral_patterns/mediator" "testing" ) func Test_MediatorPattern(t *testing.T) { // 设备注册 center := mediator.DefaultCloudCenter light := mediator.NewMockSmartLight(1) center.Register(light) fnCallAndLog := func(fn func() error) { e := fn() if e != nil { t.Log(e) } } // 创建app app := mediator.NewMockPhoneApp(mediator.DefaultCloudMediator) // 设备控制测试 fnCallAndLog(func() error { return app.LightOpen(1) }) fnCallAndLog(func() error { return app.LightSwitchMode(1, 1) }) fnCallAndLog(func() error { return app.LightSwitchMode(1, 2) }) fnCallAndLog(func() error { return app.LightClose(1) }) }
测试输出
t$ go test -v mediator_pattern_test.go === RUN Test_MediatorPattern tMockSmartLight.open, id=1 tMockSmartLight.switchMode, id=1, mode=1 tMockSmartLight.switchMode, id=1, mode=2 tMockSmartLight.close, id=1 --- PASS: Test_MediatorPattern (0.00s) PASS ok command-line-arguments 0.002s
MockPhoneApp.go
虚拟的手机app, 用于跟云中心通信, 控制智能设备
package mediator import ( "errors" "fmt" ) type MockPhoneApp struct { mediator ICloudMediator } func NewMockPhoneApp(mediator ICloudMediator) *MockPhoneApp { return &MockPhoneApp{ mediator, } } func (me *MockPhoneApp) LightOpen(id int) error { return me.lightCommand(id, "light open") } func (me *MockPhoneApp) LightClose(id int) error { return me.lightCommand(id, "light close") } func (me *MockPhoneApp) LightSwitchMode(id int, mode int) error { return me.lightCommand(id, fmt.Sprintf("light switch_mode %v", mode)) } func (me *MockPhoneApp) lightCommand(id int, cmd string) error { res := me.mediator.Command(id, cmd) if res != "OK" { return errors.New(res) } return nil }
ICloudMediator.go
云中心面向手机app的接口
package mediator type ICloudMediator interface { Command(id int, cmd string) string }
ICloudCenter.go
云中心面向智能设备的注册接口
package mediator type ICloudCenter interface { Register(dev ISmartDevice) }
ISmartDevice.go
智能设备接口
package mediator type ISmartDevice interface { ID() int Command(cmd string) string }
tMockCloudMediator.go
虚拟的云中心服务类, 面向手机app实现ICloudMediator接口, 面向智能设备实现ICloudCenter接口
package mediator import "sync" type tMockCloudMediator struct { mDevices map[int]ISmartDevice mRWMutex *sync.RWMutex } func newMockCloudMediator() ICloudMediator { return &tMockCloudMediator{ make(map[int]ISmartDevice), new(sync.RWMutex), } } func (me *tMockCloudMediator) Register(it ISmartDevice) { me.mRWMutex.Lock() defer me.mRWMutex.Unlock() me.mDevices[it.ID()] = it } func (me *tMockCloudMediator) Command(id int, cmd string) string { me.mRWMutex.RLock() defer me.mRWMutex.RUnlock() it,ok := me.mDevices[id] if !ok { return "device not found" } return it.Command(cmd) } var DefaultCloudMediator = newMockCloudMediator() var DefaultCloudCenter = DefaultCloudMediator.(ICloudCenter)
tMockSmartLight.go
虚拟的智能灯设备, 实现ISmartDevice接口
package mediator import ( "fmt" "strconv" "strings" ) type tMockSmartLight struct { id int } func NewMockSmartLight(id int) ISmartDevice { return &tMockSmartLight{ id, } } func (me *tMockSmartLight) ID() int { return me.id } func (me *tMockSmartLight) Command(cmd string) string { if cmd == "light open" { e := me.open() if e != nil { return e.Error() } } else if cmd == "light close" { e := me.close() if e != nil { return e.Error() } } else if strings.HasPrefix(cmd, "light switch_mode") { args := strings.Split(cmd, " ") if len(args) != 3 { return "invalid switch command" } n, e := strconv.Atoi(args[2]) if e != nil { return "invalid mode number" } e = me.switchMode(n) if e != nil { return e.Error() } } else { return "unrecognized command" } return "OK" } func (me *tMockSmartLight) open() error { fmt.Printf("tMockSmartLight.open, id=%v\n", me.id) return nil } func (me *tMockSmartLight) close() error { fmt.Printf("tMockSmartLight.close, id=%v\n", me.id) return nil } func (me *tMockSmartLight) switchMode(mode int) error { fmt.Printf("tMockSmartLight.switchMode, id=%v, mode=%v\n", me.id, mode) return nil }
中介者模式小结
中介者模式的优点 (1)减少类间依赖,将多对多依赖转化成一对多,降低了类间耦合。 (2)类间各司其职,符合迪米特法则。 中介者模式的缺点 中介者模式将原本多个对象直接的相互依赖变成了中介者和多个同事类的依赖关系。 当同事类越多时,中介者就会越臃肿,变得复杂且难以维护。 (摘自 谭勇德 <<设计模式就该这样学>>)
(end)
有疑问加站长微信联系(非本文作者)

Recommend
-
10
手撸golang 结构型设计模式 门面模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 门面模式 门面模式(Facade Patte...
-
11
手撸golang 结构型设计模式 装饰器模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 装饰器模式 装饰器模式(Decora...
-
16
手撸golang 行为型设计模式 委派模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 委派模式 委派模式(Delegate...
-
5
手撸golang 行为型设计模式 策略模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 策略模式 策略模式(Strategy Patter...
-
18
手撸golang 行为型设计模式 责任链模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 责任链模式 责任链模式(Chain of...
-
9
手撸golang 行为型设计模式 迭代器模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 迭代器模式 迭代器模式(Iterator...
-
11
手撸golang 行为型设计模式 备忘录模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 备忘录模式 备忘录模式(Memento P...
-
11
手撸golang 行为型设计模式 观察者模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 观察者模式 观察者模式(Observer...
-
9
手撸golang 行为型设计模式 访问者模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 访问者模式 访问者模式(Visitor P...
-
9
手撸golang 行为型设计模式 解释器模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 解释器模式 解释器模式(Interpret...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK