分享
  1. 首页
  2. 文章

手撸golang 行为型设计模式 中介者模式

老罗话编程 · · 1102 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

手撸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)


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:老罗话编程

查看原文:手撸golang 行为型设计模式 中介者模式

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
1102 次点击
1 回复 | 直到 2025年05月15日 08:33:12
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏