1. golang 包循环引用的几种解决方案
1.1. 前言
golang 为了加速编译, 不允许包循环引用。通常来说, 只要你的包规划得好, 严格规范单向调用链 (如控制层 -> 业务层 ->数据层), 一般不会出现包循环引用问题。当然现实业务往往不会这么理想, 同层级之间的不同包经常需要互相引用, 下面我就分享几种解决包循环引用的方案。
1.2. 新建公共接口包(父包), 将需要循环调用的函数或方法抽象为接口
package_i
package package_i
type PackageAInterface interface {
PrintA()
}
type PackageBInterface interface {
PrintB()
}
package_a
package package_a
import (
"cycle/package_i"
"fmt"
)
type PackageA struct {
B package_i.PackageBInterface
}
func (a PackageA) PrintA() {
fmt.Println("I'm a!")
}
func (a PackageA) PrintAll() {
a.PrintA()
a.B.PrintB()
}
package_b
package package_b
import (
"cycle/package_i"
"fmt"
)
type PackageB struct {
A package_i.PackageAInterface
}
func (b PackageB) PrintB() {
fmt.Println("I'm b!")
}
func (b PackageB) PrintAll() {
b.PrintB()
b.A.PrintA()
}
main
package main
import (
"cycle/package_a"
"cycle/package_b"
)
func main() {
a := new(package_a.PackageA)
b := new(package_b.PackageB)
a.B = b
b.A = a
a.PrintAll()
b.PrintAll()
}
1.3. 新建公共组合包(子包), 在组合包中组合调用
package_c
package package_c
import (
"cycle/package_a"
"cycle/package_b"
)
type CombileAB struct {
A *package_a.PackageA
B *package_b.PackageB
}
func (c CombileAB) PrintAll() {
c.A.PrintA()
c.B.PrintB()
}
main
package main
import (
"cycle/package_a"
"cycle/package_b"
"cycle/package_c"
)
func main() {
a := new(package_a.PackageA)
b := new(package_b.PackageB)
c := new(package_c.CombileAB)
c.A = a
c.B = b
c.PrintAll()
}
1.4. 全局存储需要相互依赖的函数, 通过关键字进行调用
callback_mgr
package callback_mgr
import (
"fmt"
"reflect"
)
var callBackMap map[string]interface{}
func init() {
callBackMap = make(map[string]interface{})
}
func RegisterCallBack(key string, callBack interface{}) {
callBackMap[key] = callBack
}
func CallBackFunc(key string, args ...interface{}) []interface{} {
if callBack, ok := callBackMap[key]; ok {
in := make([]reflect.Value, len(args))
for i, arg := range args {
in[i] = reflect.ValueOf(arg)
}
outList := reflect.ValueOf(callBack).Call(in)
result := make([]interface{}, len(outList))
for i, out := range outList {
result[i] = out.Interface()
}
return result
} else {
panic(fmt.Errorf("callBack(%s) not found", key))
}
}
package_a
package package_a
import (
"cycle/callback_mgr"
"fmt"
)
func init() {
callback_mgr.RegisterCallBack("getA", new(PackageA).GetA)
}
type PackageA struct {
}
func (a PackageA) GetA() string {
return "I'm a!"
}
func (a PackageA) PrintAll() {
fmt.Println(a.GetA())
fmt.Println(callback_mgr.CallBackFunc("getB")[0].(string))
}
package_b
package package_b
import (
"cycle/callback_mgr"
"fmt"
)
func init() {
callback_mgr.RegisterCallBack("getB", new(PackageB).GetB)
}
type PackageB struct {
}
func (b PackageB) GetB() string {
return "I'm b!"
}
func (b PackageB) PrintAll() {
fmt.Println(b.GetB())
fmt.Println(callback_mgr.CallBackFunc("getA")[0].(string))
}
main
package main
import (
"cycle/package_a"
"cycle/package_b"
)
func main() {
a := new(package_a.PackageA)
b := new(package_b.PackageB)
a.PrintAll()
b.PrintAll()
}
1.5. 不需要回调结果的可以通过事件总线 (eventBus) 解耦
eventBus
package eventBus
import (
"github.com/asaskevich/EventBus"
)
var globalEventBus EventBus.Bus
func init() {
globalEventBus = EventBus.New()
}
func Subscribe(topic string, fn interface{}) error {
return globalEventBus.Subscribe(topic, fn)
}
func SubscribeAsync(topic string, fn interface{}, transactional bool) error {
return globalEventBus.SubscribeAsync(topic, fn, transactional)
}
func Publish(topic string, args ...interface{}) {
globalEventBus.Publish(topic, args...)
}
package_a
package package_a
import (
"cycle/eventBus"
"fmt"
)
func init() {
eventBus.Subscribe("PrintA", new(PackageA).PrintA)
}
type PackageA struct {
}
func (a PackageA) PrintA() {
fmt.Println("I'm a!")
}
func (a PackageA) PrintAll() {
a.PrintA()
eventBus.Publish("PrintB")
}
package_b
package package_b
import (
"cycle/eventBus"
"fmt"
)
func init() {
eventBus.Subscribe("PrintB", new(PackageB).PrintB)
}
type PackageB struct {
}
func (b PackageB) PrintB() {
fmt.Println("I'm b!")
}
func (b PackageB) PrintAll() {
b.PrintB()
eventBus.Publish("PrintA")
}
总结
到此这篇关于golang包循环引用的几种解决方案的文章就介绍到这了,更多相关golang包循环引用内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!