Go中的控制反转 IoC

以嵌入组合的方式实现控制反转 IoC:

控制反转是一种解耦思想,将原本耦合在业务逻辑中的控制逻辑单独拆出来实现,不再让业务逻辑在处理业务的同时还要去实现控制逻辑,而是专注处理业务。在业务逻辑代码中耦合进控制逻辑,会导致在编写业务逻辑时需要处理业务之外的事,而且控制逻辑耦合进业务中,只适用于当前业务逻辑,无法被复用。

go 复制代码
// 以嵌入组合的方式实现控制反转 IoC
package main

import (
	"errors"
	"fmt"
)

// 2.被要求:新增一 'undo 后悔' 功能。
// 3.解决办法:定义单独(通用的)控制逻辑,别的数据结构也可能会用到
//   即:控制逻辑封装在 Undo 中,业务逻辑 IntSet 只关心处理整型数据
type Undo []func() // 函数切片

func (undo *Undo) Add(fn func()) { //undo入栈
	*undo = append(*undo, fn)
}

func (undo *Undo) Undo() error {
	functions := *undo
	if len(functions) == 0 {
		return errors.New("No functions to undo")
	}
	index := len(functions) - 1
	if fn := functions[index]; fn != nil {
		fn()
		functions[index] = nil  // 垃圾回收
	}
	*undo = functions[:index] // undo出栈操作
	return nil
}

// ----------------------------------------------
type IntSet struct {
	data map[int]bool  // 1.原本的处理整形数据的结构
	undo Undo // 3.解决办法:并在此处嵌入一个 Undo 结构,间接实现 undo 功能
}

func NewIntSet() IntSet {
	return IntSet{data: make(map[int]bool)}
}

func (set *IntSet) Add(x int) {
	// set.data[x] = true  //原来逻辑
	// 改为
	if !set.Contains(x) {
		set.data[x] = true
		set.undo.Add(func() { set.Delete(x) })
	} else {
		set.undo.Add(nil)
	}
}

func (set *IntSet) Delete(x int) {
	// delete(set.data, x) //原来逻辑
	//改为
	if set.Contains(x) {
		delete(set.data, x)
		set.undo.Add(func() { set.Add(x) })
	} else {
		set.undo.Add(nil)
	}
}

func (set *IntSet) Contains(x int) bool {
	return set.data[x]
}

// 3.新增
func (set *IntSet) Undo() error {
	return set.undo.Undo()
}

// ----------------------------------------------
func main() {
	a := NewIntSet()
	for i := 1; i < 11; i++ {
		a.Add(i)
	}
	fmt.Printf("%v\n", a) //map[1:true 2:true 3:true 4:true 5:true 6:true 7:true 8:true 9:true 10:true]
	fmt.Printf("%v\n", a.Contains(2))

	a.Delete(2)
	fmt.Printf("%v\n", a) //map[1:true 3:true 4:true 5:true 6:true 7:true 8:true 9:true 10:true]
	fmt.Printf("%v\n", a.Contains(2))

	a.Undo()
	fmt.Printf("%v\n", a) //map[1:true 2:true 3:true 4:true 5:true 6:true 7:true 8:true 9:true 10:true]
	fmt.Printf("%v\n", a.Contains(2))

	fmt.Printf("%v\n", a.Contains(4))
	a.Delete(4)
	fmt.Printf("%v\n", a) //map[1:true 2:true 3:true 5:true 6:true 7:true 8:true 9:true 10:true]
	fmt.Printf("%v\n", a.Contains(4))
	a.Delete(7)
	fmt.Printf("%v\n", a) //map[1:true 2:true 3:true 5:true 6:true 8:true 9:true 10:true]
	fmt.Printf("%v\n", a.Contains(7))

	a.Undo()
	fmt.Printf("%v\n", a) //map[1:true 2:true 3:true 5:true 6:true 7:true 8:true 9:true 10:true]
	fmt.Printf("%v\n", a.Contains(7))
	a.Undo()
	fmt.Printf("%v\n", a) //map[1:true 2:true 3:true 4:true 5:true 6:true 7:true 8:true 9:true 10:true]
	fmt.Printf("%v\n", a.Contains(4))
}
相关推荐
超级架构师11 小时前
PRAXO-CORE 2.5.0:用 conformance 和显式边界构建 Go Agent 框架
开发语言·人工智能·后端·golang·ai编程·智能体框架·praxo-core
我就是全世界15 小时前
OpenCode Go 套餐划算吗:先看你用哪个模型
开发语言·后端·golang
小杨互联网18 小时前
Go 现代 CLI 工具离线镜像合集
开发语言·后端·golang·开源·go·命令行
hourinX21 小时前
从直接填格子到筛选图案:头像生成这部分是怎样改过来的—— gdenticon 重构日志(三)
go
microrain1 天前
跟着一条属性报文走一遍 SagooIoT 的接入链路
物联网·架构·golang·sagooiot
CodeGL1 天前
微服务框架——go-zero
微服务·架构·golang
我不会起名字3221 天前
Redis 从 0 到 1(十三):分布式锁被误删、锁不住?Go 无 Lua 实现 3 级防御
redis·go·分布式锁·watch·setnx
hourinX2 天前
从 v1 到 v2,我重新拆了头像生成的整条链路—— gdenticon 重构日志(二)
go
紧跟先前的步伐2 天前
Go AI Agent 实战 22|完善 Agent 执行循环:从工具调用到最终回答
人工智能·ai·golang
后台模板学习2 天前
Go Web开发中任务调度框架的源码解析与高可用实现方案
开发语言·后端·golang