golang包循环引用的几种解决方案总结
短信预约 -IT技能 免费直播动态提醒
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包循环引用内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341