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


本文摘自网络,作者,侵删。

手撸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 行为型设计模式 中介者模式

相关阅读 >>

Goland解析json获取指定字段内容

Go语言函数引用传递值

为什么选择 Golang?彻底解决争论

小米滴滴等百家企业因疫情寻求贷款;报告称it人最想学习 Go 和 python;中国手机销量或减少5

Go - 统一定义 api 错误码

聊聊Golang的ddd项目结构

Go并发处理

Golang 架构设计原则 依赖倒置原则

测试平台(序)

Golang之不可重入函数实现

更多相关阅读请进入《Go》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...