golang包循环引用
云满笔记 人气:01. 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") }
总结
加载全部内容