共计 4390 个字符,预计需要花费 11 分钟才能阅读完成。
手撸 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)
正文完