golang包循环引用的几种解决方案

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/,如有侵权,请联系删除。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

Golang Gin实践 番外 请入门 Makefile

<h1GolangGin实践番外请入门Makefile</h1<p原文地址:<ahref"https://github.com/EDDYCJY/blog/blob/master/golang/gin/20180826Gin%E5%AE%9E%E8%B7%B5%E7%95%AA%E5%A4%96%E8%AF%B7%E5%85%A5

Apollo使用文档(Java)

1、apolo的github上的文档很全,大家可以去github上查看下面是java客户端使用文档https://github.com/ctripcorp/apollo/wiki/Java%E5%AE%A2%E6%88%B7%E7%AB%AF%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97(https://www.oschin

Java 入门进阶

Java入门进阶發表於20150416http://xielong.me/2015/04/16/%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%B7%A5%E7%A8%8B%E5%B8%88%E5%85%A5%E9%97%A8%E4%B8%8E%E8%BF%9B%E9%98%B6Java%E7%89%88/