網站首頁 編程語言 正文
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") }
總結
原文鏈接:https://blog.csdn.net/wan212000/article/details/123261256
相關推薦
- 2023-05-06 Flutter學習之SliverList和SliverGird的使用詳解_Android
- 2022-05-29 ASP.NET?Core使用HttpClient調用WebService_實用技巧
- 2022-10-29 Spring的純注解配置詳解
- 2023-08-28 vscode里面報:‘xxx‘ is assigned a value but never used
- 2022-02-12 Flutter項目中有些依賴不支持64位的library的解決方式
- 2023-02-18 React錯誤的習慣用法分析詳解_React
- 2022-05-17 Redis調用Lua腳本及使用場景快速掌握_Redis
- 2023-01-27 C#實現拆分合并Word表格中的單元格_C#教程
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支