golang包循環(huán)引用的幾種解決方案總結(jié)
1. golang 包循環(huán)引用的幾種解決方案
1.1. 前言
golang 為了加速編譯, 不允許包循環(huán)引用。通常來說, 只要你的包規(guī)劃得好, 嚴(yán)格規(guī)范單向調(diào)用鏈 (如控制層 -> 業(yè)務(wù)層 ->數(shù)據(jù)層), 一般不會出現(xiàn)包循環(huán)引用問題。當(dāng)然現(xiàn)實業(yè)務(wù)往往不會這么理想, 同層級之間的不同包經(jīng)常需要互相引用, 下面我就分享幾種解決包循環(huán)引用的方案。
1.2. 新建公共接口包(父包), 將需要循環(huán)調(diào)用的函數(shù)或方法抽象為接口
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. 新建公共組合包(子包), 在組合包中組合調(diào)用
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. 全局存儲需要相互依賴的函數(shù), 通過關(guān)鍵字進(jìn)行調(diào)用
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. 不需要回調(diào)結(jié)果的可以通過事件總線 (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")
}
總結(jié)
到此這篇關(guān)于golang包循環(huán)引用的幾種解決方案的文章就介紹到這了,更多相關(guān)golang包循環(huán)引用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一文帶你搞懂Golang依賴注入的設(shè)計與實現(xiàn)
在現(xiàn)代的 web 框架里面,基本都有實現(xiàn)了依賴注入的功能,可以讓我們很方便地對應(yīng)用的依賴進(jìn)行管理。今天我們來看看 go 里面實現(xiàn)依賴注入的一種方式,感興趣的可以了解一下2023-01-01
Golang import 導(dǎo)入包語法及一些特殊用法詳解
這篇文章主要介紹了Golang import 導(dǎo)入包語法及一些特殊用法,需要的朋友可以參考下2020-02-02
windows下使用vscode搭建golang環(huán)境并調(diào)試的過程
這篇文章主要介紹了在windows下使用vscode搭建golang環(huán)境并進(jìn)行調(diào)試,主要包括安裝方法及環(huán)境變量配置技巧,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-09-09

