在go語言中,控制反轉(IoC)是物件導向程式設計中的一種設計原則,可以用來減少電腦程式碼之間的耦合度,就是程式碼控制權從商業程式碼「反轉”到框架代碼。常見的控制反轉方式叫做依賴注入,還有一種方式叫做「依賴查找」;透過控制反轉,物件在被創建的時候,由一個調控系統內所有物件的外界實體將其所依賴的物件的引用傳遞給它。
本教學操作環境:windows7系統、GO 1.18版本、Dell G3電腦。
控制反轉是什麼
控制反轉(Inversion of Control,縮寫為IoC),是物件導向程式設計中的一種設計原則,可以用來減低電腦程式碼之間的耦合度。其中最常見的方式叫做依賴注入(Dependency Injection,簡稱DI),還有一種方式叫做「依賴查找」(Dependency Lookup)。透過控制反轉,物件在被創建的時候,由一個調控系統內所有物件的外界實體將其所依賴的物件的引用傳遞給它。也可以說,依賴被注入到物件中。
講得通俗一點,假如我有一個控制器,UserController,它可以Code,Read,Eat ,當然它還有隱式的__construct建構函數,__destruct析構函數,我們知道這些預設函數在特定的情景會自己觸發,例如初始化的時候,生命週期結束釋放資源的時候,但是我們如果假如這些函數本身都不會自己觸發,那麼我們作為作者怎麼去讓他執行。其實我的控制器還有ArticleController ,YouBadBadController,我要怎麼去處理。
各幹各的User你幹活之前先去構建一下自己,Article你幹活之前也去構建一下自己這個情況短板就很明顯了,後面介紹,每個控制器都要去各幹各的,其實都是Controller ,在處理公共行為的時候,其實我們可以藉組外部實現和管理。我們不用預設的魔法函數了,介紹一個具體場景,假如我現在需要每個控制器都要實作並呼叫一個handle函數。我們怎麼合理去完成,假如現在還要執行一個run 方法,每個控制器添加完run函數之後,我們是不是還要寫他們的調度;
控制反轉統一管理這個操作是不是可以讓一個公共的ControllerService幫忙handle就行了,我們現在不考慮繼承。
class ControllerService{ public functiondo(){ ->handle(); } //去吧比卡丘; } }
等等,小智不投精靈球怎麼去吧,小智呢?我們需要把控制方帶過來
class ControllerService{ public $handler; public function __construct($handler){ $this->handler=$handler ; } //通过构造函数带入; } // public function setHandler($handler){ $this->handler->handle(); } //通过setter带入; } public function do(){ $this->handler->handle(); } //去吧比卡丘; } } new ControllerService()->setHandler(new UserController())->do();
這樣控制權已經反轉給ControllerService了;
Go語言中的interface 反射機制也是Ioc的體現
Golang 控制反轉(IOC)在工程上應用
設計
所採用的第三方函式庫:https: //github.com/berkaroad/ioc
使用起來還是比較簡單的,無非就是RegisterTo, Invoke,但是任何的函式庫都需要結合框架起來才有意義。
一提到松耦合,在GO中很容易就想到介面(interface),所以我們用介面實現的各個層之間的鬆散耦合。
依照傳統的MVC框架,一般服務端會有幾種分層,Controler層、Service層、Module層 從上到下,如何將Ioc結合在框架中才是值得探討的事情。
目錄
呼叫結構:由於沒有服務,main函數充當的是Controler、Service是服務層、Module是數據層、Resource是儲存層、app是各種介面的定義
main-->Service-->Module-->Resource
為了示範服務之間的調用,我們定義了service1和service2兩種服務
實作
。各層的介面定義
package app type Service1 interface { AddData(string) DelData(string) } type Service2 interface { AddData(string) DelData(string) } type Module interface { DataToSave(string) DataToRemove(string) } type Resource interface { Save(string) Remove(string) }
IOC初始化
package app import ( "github.com/berkaroad/ioc" "github.com/spf13/viper" ) func GetOrCreateRootContainer() ioc.Container { v := viper.Get("runtime.container") if v == nil { v = ioc.NewContainer() viper.Set("runtime.container", v) } return v.(ioc.Container) }
這裡其實怎麼實作都行,只是一個單例NewContainer就可以
儲存層(自下而上)
package resource import ( "fmt" "github.com/berkaroad/ioc" "github.com/zhaoshoucheng/hodgepodge/IoC/app" ) type ResourceObj struct { name string } func (r *ResourceObj) Save(str string) { fmt.Println(r.name, " Save ", str) } func (r *ResourceObj) Remove(str string) { fmt.Println(r.name, " Remove ", str) } func init() { mo := &ResourceObj{name: "mongo"} // static assert 静态断言类型检测 func(t app.Resource) {}(mo) app.GetOrCreateRootContainer().RegisterTo(mo, (*app.Resource)(nil), ioc.Singleton) //rd := &ResourceObj{name: "redis"} 实现是用的map,所以mong会被覆盖 //app.GetOrCreateRootContainer().RegisterTo(rd, (*app.Resource)(nil), ioc.Singleton) }
RegisterTo是註冊過程,在mo物件後續會當作app.Resource介面的實作來使用,其底層實作是一個map
資料層
package module import ( "fmt" "github.com/berkaroad/ioc" "github.com/zhaoshoucheng/hodgepodge/IoC/app" ) var ( rs app.Resource ) type ModuleObj struct { } func (mo *ModuleObj) DataToSave(str string) { fmt.Println("ModuleObj DataToSave ", str) rs.Save(str) } func (mo *ModuleObj) DataToRemove(str string) { fmt.Println("ModuleObj DataToRemove ", str) rs.Remove(str) } func init() { mo := &ModuleObj{} // static assert 静态断言类型检测 func(t app.Module) {}(mo) app.GetOrCreateRootContainer().RegisterTo(mo, (*app.Module)(nil), ioc.Singleton) app.GetOrCreateRootContainer().Invoke(func(r app.Resource) { rs = r }) }
因為我們之前app.Resource已經註冊過,所以這裡Invoke的時候就可以取得到實作該介面的物件
服務層##package service
import (
"fmt"
"github.com/berkaroad/ioc"
"github.com/zhaoshoucheng/hodgepodge/IoC/app"
)
var (
module app.Module
service2 app.Service2
)
type Service1 struct {
}
func (s1 *Service1) AddData(str string) {
service2.AddData(str)
fmt.Println("Service1 AddData ", str)
module.DataToSave(str)
}
func (s1 *Service1) DelData(str string) {
service2.DelData(str)
fmt.Println("Service1 DelData ", str)
module.DataToRemove(str)
}
func init() {
s1 := &Service1{}
s2 := &Service2{}
service2 = s2
//static assert 静态断言做类型检查
func(t app.Service1) {}(s1)
func(t app.Service2) {}(s2)
app.GetOrCreateRootContainer().RegisterTo(s1, (*app.Service1)(nil), ioc.Singleton)
app.GetOrCreateRootContainer().RegisterTo(s2, (*app.Service2)(nil), ioc.Singleton)
app.GetOrCreateRootContainer().Invoke(func(mod app.Module) {
module = mod
})
}
Mainpackage main
import (
"github.com/zhaoshoucheng/hodgepodge/IoC/app"
_ "github.com/zhaoshoucheng/hodgepodge/IoC/resource"
_ "github.com/zhaoshoucheng/hodgepodge/IoC/module"
_ "github.com/zhaoshoucheng/hodgepodge/IoC/service"
)
func main() {
var s1 app.Service1
app.GetOrCreateRootContainer().Invoke(func(service app.Service1) {
s1 = service
})
s1.AddData("IOC Test")
}
測試
思考
#######我们为什么要用到Ioc呢?个人感觉有几点好处
1.解决各种依赖问题,写GO可能都遇到过循环引用问题,越是复杂的系统就越有可能出现这种混乱的调用现象。
2.实现了很好的扩展性,如果存储层想从redis切换到mongo,定义一个相同的对象,替换注册对象就可以轻松实现。
3.易使用,随时随地可以通过Invoke获取相应的接口对象。
问题
难道就没有问题吗?
当然有,就是引用顺序的问题,也就是先register 还是先invoke 这个在例子中感觉很简单,但是在工程中很容易出错
_ "github.com/zhaoshoucheng/hodgepodge/IoC/module" _ "github.com/zhaoshoucheng/hodgepodge/IoC/resource" _ "github.com/zhaoshoucheng/hodgepodge/IoC/service"
_ "github.com/zhaoshoucheng/hodgepodge/IoC/resource" _ "github.com/zhaoshoucheng/hodgepodge/IoC/module" _ "github.com/zhaoshoucheng/hodgepodge/IoC/service"
第一种写法就会崩溃,第二种正确
原因第一种module 的init 先执行,app.Resource的对象还没有注册。所以init的先后顺序很重要
但这个是凭借字节码进行的排序,有时IDE还不让我们改,所以需要一些控制器去处理这种情况。
以上是go語言中控制反轉是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

golangisidealforperformance-Critical-clitageAppations and ConcurrentPrompromming,而毛皮刺激性,快速播種和可及性。 1)forhigh-porformanceneeds,pelectgolangduetoitsefefsefefseffifeficefsefeflicefsiveficefsiveandconcurrencyfeatures.2)fordataa-fordataa-fordata-fordata-driventriventriventriventriventrivendissp pynonnononesp

Golang通過goroutine和channel實現高效並發:1.goroutine是輕量級線程,使用go關鍵字啟動;2.channel用於goroutine間安全通信,避免競態條件;3.使用示例展示了基本和高級用法;4.常見錯誤包括死鎖和數據競爭,可用gorun-race檢測;5.性能優化建議減少channel使用,合理設置goroutine數量,使用sync.Pool管理內存。

Golang更適合系統編程和高並發應用,Python更適合數據科學和快速開發。 1)Golang由Google開發,靜態類型,強調簡潔性和高效性,適合高並發場景。 2)Python由GuidovanRossum創造,動態類型,語法簡潔,應用廣泛,適合初學者和數據處理。

Golang在性能和可擴展性方面優於Python。 1)Golang的編譯型特性和高效並發模型使其在高並發場景下表現出色。 2)Python作為解釋型語言,執行速度較慢,但通過工具如Cython可優化性能。

Go語言在並發編程、性能、學習曲線等方面有獨特優勢:1.並發編程通過goroutine和channel實現,輕量高效。 2.編譯速度快,運行性能接近C語言。 3.語法簡潔,學習曲線平緩,生態系統豐富。

Golang和Python的主要區別在於並發模型、類型系統、性能和執行速度。 1.Golang使用CSP模型,適用於高並發任務;Python依賴多線程和GIL,適合I/O密集型任務。 2.Golang是靜態類型,Python是動態類型。 3.Golang編譯型語言執行速度快,Python解釋型語言開發速度快。

Golang通常比C 慢,但Golang在並發編程和開發效率上更具優勢:1)Golang的垃圾回收和並發模型使其在高並發場景下表現出色;2)C 通過手動內存管理和硬件優化獲得更高性能,但開發複雜度較高。

Golang在雲計算和DevOps中的應用廣泛,其優勢在於簡單性、高效性和並發編程能力。 1)在雲計算中,Golang通過goroutine和channel機制高效處理並發請求。 2)在DevOps中,Golang的快速編譯和跨平台特性使其成為自動化工具的首選。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

SublimeText3漢化版
中文版,非常好用

Dreamweaver Mac版
視覺化網頁開發工具

Atom編輯器mac版下載
最受歡迎的的開源編輯器

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。