golang包循环引用的几种解决方案
发表于2020年11月2日2020年11月3日 作者 libuba
一、前言
golang为了加速编译,不允许包循环引用。通常来说,只要你的包规划得好,严格规范单向调用链(如控制层->业务层->数据层),一般不会出现包循环引用问题。当然现实业务往往不会这么理想,同层级之间的不同包经常需要互相引用,下面我就分享几种解决包循环引用的方案。
二、新建公共接口包(父包),将需要循环调用的函数或方法抽象为接口
- package_i
1package package\_i 2 3type PackageAInterface interface { 4 PrintA() 5} 6 7type PackageBInterface interface { 8 PrintB() 9}
- package_a
1package package\_a 2 3import ( 4 "cycle/package\_i" 5 "fmt" 6) 7 8type PackageA struct { 9 B package\_i.PackageBInterface 10} 11 12func (a PackageA) PrintA() { 13 fmt.Println("I'm a!") 14} 15 16func (a PackageA) PrintAll() { 17 a.PrintA() 18 a.B.PrintB() 19}
- package_b
1package package\_b 2 3import ( 4 "cycle/package\_i" 5 "fmt" 6) 7 8type PackageB struct { 9 A package\_i.PackageAInterface 10} 11 12func (b PackageB) PrintB() { 13 fmt.Println("I'm b!") 14} 15 16func (b PackageB) PrintAll() { 17 b.PrintB() 18 b.A.PrintA() 19}
- main
1package main 2 3import ( 4 "cycle/package\_a" 5 "cycle/package\_b" 6) 7 8func main() { 9 a := new(package\_a.PackageA) 10 b := new(package\_b.PackageB) 11 a.B \= b 12 b.A \= a 13 a.PrintAll() 14 b.PrintAll() 15}
三、新建公共组合包(子包),在组合包中组合调用
- package_c
1package package\_c 2 3import ( 4 "cycle/package\_a" 5 "cycle/package\_b" 6) 7 8type CombileAB struct { 9 A \*package\_a.PackageA 10 B \*package\_b.PackageB 11} 12 13func (c CombileAB) PrintAll() { 14 c.A.PrintA() 15 c.B.PrintB() 16}
- main
1package main 2 3import ( 4 "cycle/package\_a" 5 "cycle/package\_b" 6 "cycle/package\_c" 7) 8 9func main() { 10 a := new(package\_a.PackageA) 11 b := new(package\_b.PackageB) 12 c := new(package\_c.CombileAB) 13 c.A \= a 14 c.B \= b 15 c.PrintAll() 16}
四、全局存储需要相互依赖的函数,通过关键字进行调用
- callback_mgr
1package callback\_mgr 2 3import ( 4 "fmt" 5 "reflect" 6) 7 8var callBackMap map\[string\]interface{} 9 10func init() { 11 callBackMap \= make(map\[string\]interface{}) 12} 13 14func RegisterCallBack(key string, callBack interface{}) { 15 callBackMap\[key\] \= callBack 16} 17 18func CallBackFunc(key string, args ...interface{}) \[\]interface{} { 19 if callBack, ok := callBackMap\[key\]; ok { 20 in := make(\[\]reflect.Value, len(args)) 21 for i, arg := range args { 22 in\[i\] \= reflect.ValueOf(arg) 23 } 24 outList := reflect.ValueOf(callBack).Call(in) 25 result := make(\[\]interface{}, len(outList)) 26 for i, out := range outList { 27 result\[i\] \= out.Interface() 28 } 29 return result 30 } else { 31 panic(fmt.Errorf("callBack(%s) not found", key)) 32 } 33}
- package_a
1package package\_a 2 3import ( 4 "cycle/callback\_mgr" 5 "fmt" 6) 7 8func init() { 9 callback\_mgr.RegisterCallBack("getA", new(PackageA).GetA) 10} 11 12type PackageA struct { 13} 14 15func (a PackageA) GetA() string { 16 return "I'm a!" 17} 18 19func (a PackageA) PrintAll() { 20 fmt.Println(a.GetA()) 21 fmt.Println(callback\_mgr.CallBackFunc("getB")\[0\].(string)) 22}
- package_b
1package package\_b 2 3import ( 4 "cycle/callback\_mgr" 5 "fmt" 6) 7 8func init() { 9 callback\_mgr.RegisterCallBack("getB", new(PackageB).GetB) 10} 11 12type PackageB struct { 13} 14 15func (b PackageB) GetB() string { 16 return "I'm b!" 17} 18 19func (b PackageB) PrintAll() { 20 fmt.Println(b.GetB()) 21 fmt.Println(callback\_mgr.CallBackFunc("getA")\[0\].(string)) 22}
- main
1package main 2 3import ( 4 "cycle/package\_a" 5 "cycle/package\_b" 6) 7 8func main() { 9 a := new(package\_a.PackageA) 10 b := new(package\_b.PackageB) 11 a.PrintAll() 12 b.PrintAll() 13}
五、不需要回调结果的可以通过事件总线(eventBus)解耦
- eventBus
1package eventBus 2 3import ( 4 "github.com/asaskevich/EventBus" 5) 6 7var globalEventBus EventBus.Bus 8 9func init() { 10 globalEventBus \= EventBus.New() 11} 12 13func Subscribe(topic string, fn interface{}) error { 14 return globalEventBus.Subscribe(topic, fn) 15} 16 17func SubscribeAsync(topic string, fn interface{}, transactional bool) error { 18 return globalEventBus.SubscribeAsync(topic, fn, transactional) 19} 20 21func Publish(topic string, args ...interface{}) { 22 globalEventBus.Publish(topic, args...) 23}
- package_a
1package package\_a 2 3import ( 4 "cycle/eventBus" 5 "fmt" 6) 7 8func init() { 9 eventBus.Subscribe("PrintA", new(PackageA).PrintA) 10} 11 12type PackageA struct { 13} 14 15func (a PackageA) PrintA() { 16 fmt.Println("I'm a!") 17} 18 19func (a PackageA) PrintAll() { 20 a.PrintA() 21 eventBus.Publish("PrintB") 22}
- package_b
1package package\_b 2 3import ( 4 "cycle/eventBus" 5 "fmt" 6) 7 8func init() { 9 eventBus.Subscribe("PrintB", new(PackageB).PrintB) 10} 11 12type PackageB struct { 13} 14 15func (b PackageB) PrintB() { 16 fmt.Println("I'm b!") 17} 18 19func (b PackageB) PrintAll() { 20 b.PrintB() 21 eventBus.Publish("PrintA") 22}
分类: golang随笔
标签: go
本文转自 https://libuba.com/2020/11/02/golang%E5%8C%85%E5%BE%AA%E7%8E%AF%E5%BC%95%E7%94%A8%E7%9A%84%E5%87%A0%E7%A7%8D%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/,如有侵权,请联系删除。
