• golang设计模式——中介模式


    中介模式

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-627Y6Nue-1661349537075)(C:/Users/86158/AppData/Roaming/Typora/typora-user-images/image-20220824095652355.png)]

    中介者模式是设计模式系列中最后一个模式。中介者模式能帮大家更好的维护系统。

    中介者模式:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变他们之间的交互。

    UML

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CCXOusCF-1661349537076)(C:/Users/86158/AppData/Roaming/Typora/typora-user-images/image-20220824100719886.png)]

    分析

    对于定义,大家比较容易理解。由中介者控制所有的交互,Colleague对象无需相互感知。

    使用中介者模式有个前提,Colleague之间相互影响,即一个Colleague的变化会影响其它Colleague。

    我们再来看UML。通过UML可以看出

    • Mediator包含所有Colleague,这是中介者能控制所有交互的基础
    • Colleague包含Mediator,Colleague变化可直接通知Mediator,这是Colleague无需知道其它Colleague的基础,只需知道Mediator即可

    根据前面提到的前提和UML类图,我们思考的再深一些,ConcreteColleague是否有相同父类并不重要,只要Mediator包含所有ConcreteColleague,ConcreteColleague有Mediator,中介者模式依然有效。

    应用场景

    使用中介者模式有哪些好处?

    我们设想一种场景,假设有多个Colleague,分别为Colleague1、Colleague2、Colleague3、Colleague4,如果一个Colleague的动作会影响到其它Colleague,便形成多对多的网状结构,随着Colleague增加,会更加难以管理。如果使用中介者模式,会变成一对多的星状结构,所有Colleague只和Mediator相关,管理复杂度降低。

    在实际工作中,没碰到过网状结构,所以没用过中介者模式。比较合适的例子,如GoLand中的注册,点击Active Goland/Evaluate for free,会显示不同的UI组件。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8JquMClb-1661349537077)(C:/Users/86158/AppData/Roaming/Typora/typora-user-images/image-20220824214549199.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vTEo9hfh-1661349537077)(C:/Users/86158/AppData/Roaming/Typora/typora-user-images/image-20220824214602978.png)]

    代码实现

    我们简单实现GoLand激活的例子。

    package main
    
    import "fmt"
    
    /**
     * @Description: 中介者接口
     */
    type Mediator interface {
    	Process(colleague UIColleague)
    }
    
    /**
     * @Description: 真正的中介者
     */
    type UIMediator struct {
    	activate *ActivateColleague
    	evaluate *EvaluateColleague
    	text     *TextColleague
    }
    
    /**
     * @Description: 中介者大总管,处理所有事情
     * @receiver u
     */
    func (u *UIMediator) Process(colleague UIColleague) {
    	if colleague == u.activate { //如果是激活
    		u.evaluate.Show("试用内容隐藏")
    		u.text.Show("请输入激活码")
    	} else if colleague == u.evaluate { //如果是试用
    		u.activate.Show("激活内容隐藏")
    		u.text.Show("请出入激活时间")
    	}
    }
    
    /**
     * @Description: Colleague接口
     */
    type UIColleague interface {
    	Action()
    }
    
    /**
     * @Description: 激活UI
     */
    type ActivateColleague struct {
    	mediator Mediator
    }
    
    /**
     * @Description: 激活触发的动作
     * @receiver a
     */
    func (a *ActivateColleague) Action() {
    	a.mediator.Process(a)
    }
    
    /**
     * @Description: 激活UI显示内容
     * @receiver e
     * @param text
     */
    func (e *ActivateColleague) Show(text string) {
    	fmt.Println(text)
    }
    
    /**
     * @Description: 试用UI
     */
    type EvaluateColleague struct {
    	mediator Mediator
    }
    
    /**
     * @Description: 试用触发的动作
     * @receiver e
     */
    func (e *EvaluateColleague) Action() {
    	e.mediator.Process(e)
    }
    
    /**
     * @Description: 试用UI显示内容
     * @receiver e
     * @param text
     */
    func (e *EvaluateColleague) Show(text string) {
    	fmt.Println(text)
    }
    
    /**
     * @Description: 文案UI
     */
    type TextColleague struct {
    	mediator Mediator
    }
    
    /**
     * @Description: 文案触发动作
     * @receiver t
     */
    func (t *TextColleague) Action() {
    	t.mediator.Process(t)
    }
    
    /**
     * @Description: 文案显示内容
     * @receiver t
     * @param text
     */
    func (t *TextColleague) Show(text string) {
    	fmt.Println(text)
    }
    
    func main() {
    	//初始化
    	m := &UIMediator{}
    
    	activate := &ActivateColleague{
    		mediator: m,
    	}
    	evaluate := &EvaluateColleague{
    		mediator: m,
    	}
    	text := &TextColleague{
    		mediator: m,
    	}
    
    	m.activate = activate
    	m.evaluate = evaluate
    	m.text = text
    	//点击激活
    	fmt.Println("-----------------点击激活")
    	activate.Action()
    	//点击试用
    	fmt.Println("-----------------点击试用")
    	evaluate.Action()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137

    输出:

    —————–点击激活

    试用内容隐藏

    请输入激活码

    —————–点击试用

    激活内容隐藏

    请出入激活时间

    从代码中可以看出,Mediator有所有的UI,UI只调用Mediator,无需知道其它UI,Mediator通过Process处理所有操作。当今后增加新UI,只需Mediator知道即可,不必改动其它UI。当然,要防止Mediator变成超级大类,这需要根据实际情况做取舍。

    实例

    代码

    // Package mediator 中介模式
    // 采用原课程的示例,并且做了一些裁剪
    // 假设我们现在有一个较为复杂的对话框,里面包括,登录组件,注册组件,以及选择框
    // 当选择框选择“登录”时,展示登录相关组件
    // 当选择框选择“注册”时,展示注册相关组件
    package mediator
    
    import (
    	"fmt"
    	"reflect"
    )
    
    // Input 假设这表示一个输入框
    type Input string
    
    // String String
    func (i Input) String() string {
    	return string(i)
    }
    
    // Selection 假设这表示一个选择框
    type Selection string
    
    // Selected 当前选中的对象
    func (s Selection) Selected() string {
    	return string(s)
    }
    
    // Button 假设这表示一个按钮
    type Button struct {
    	onClick func()
    }
    
    // SetOnClick 添加点击事件回调
    func (b *Button) SetOnClick(f func()) {
    	b.onClick = f
    }
    
    // IMediator 中介模式接口
    type IMediator interface {
    	HandleEvent(component interface{})
    }
    
    // Dialog 对话框组件
    type Dialog struct {
    	LoginButton         *Button
    	RegButton           *Button
    	Selection           *Selection
    	UsernameInput       *Input
    	PasswordInput       *Input
    	RepeatPasswordInput *Input
    }
    
    // HandleEvent HandleEvent
    func (d *Dialog) HandleEvent(component interface{}) {
    	switch {
    	case reflect.DeepEqual(component, d.Selection):
    		if d.Selection.Selected() == "登录" {
    			fmt.Println("select login")
    			fmt.Printf("show: %s\n", d.UsernameInput)
    			fmt.Printf("show: %s\n", d.PasswordInput)
    		} else if d.Selection.Selected() == "注册" {
    			fmt.Println("select register")
    			fmt.Printf("show: %s\n", d.UsernameInput)
    			fmt.Printf("show: %s\n", d.PasswordInput)
    			fmt.Printf("show: %s\n", d.RepeatPasswordInput)
    		}
    		// others, 如果点击了登录按钮,注册按钮
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    测试

    package mediator
    
    import "testing"
    
    func TestDemo(t *testing.T) {
    	usernameInput := Input("username input")
    	passwordInput := Input("password input")
    	repeatPwdInput := Input("repeat password input")
    
    	selection := Selection("登录")
    	d := &Dialog{
    		Selection:           &selection,
    		UsernameInput:       &usernameInput,
    		PasswordInput:       &passwordInput,
    		RepeatPasswordInput: &repeatPwdInput,
    	}
    	d.HandleEvent(&selection)
    
    	regSelection := Selection("注册")
    	d.Selection = &regSelection
    	d.HandleEvent(&regSelection)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    总结

    中介者模式算是聚而歼之的模式,因为从分而治之上讲,对应的操作应该让每一个Colleague自行管理,但这样做,Colleague之间需要相互了解,沟通成本太高。

    如果收拢到Mediator,整体效率会高很多,但Mediator存在成为上帝类的可能,反而导致不好维护。

    这是不是特别像实际生活。所以说世上的处理方案没有定法,能够更好的解决问题就是最好的。共勉。

  • 相关阅读:
    实验3.2 Numpy应用
    案例研究丨运动品牌On昂跑如何通过DTC创新实现全球化战略
    [python 刷题] 3 Longest Substring Without Repeating Characters
    Arrays.fill(dp, Integer.MAX_VALUE)
    盲盒电商模式:神秘感+趣味性,轻松实现社交购物
    【密码学篇】虚拟专用网技术原理与应用(商密)
    java计算机毕业设计springboot+vue学生宿舍管理系统 elementui
    Python+大数据-知行教育(七)-学生出勤主题看板
    2023年上半年软考中级数据库系统工程师如何高效备考?难吗?
    第二期 微信云开发之位置信息获取(wx.getLocation)
  • 原文地址:https://blog.csdn.net/qq_53267860/article/details/126513569