這篇文章主要介紹了go語(yǔ)言控制反轉(zhuǎn)指的是什么的相關(guān)知識(shí),內(nèi)容詳細(xì)易懂,操作簡(jiǎn)單快捷,具有一定借鑒價(jià)值,相信大家閱讀完這篇go語(yǔ)言控制反轉(zhuǎn)指的是什么文章都會(huì)有所收獲,下面我們一起來(lái)看看吧。
創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),惠民企業(yè)網(wǎng)站建設(shè),惠民品牌網(wǎng)站建設(shè),網(wǎng)站定制,惠民網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷,網(wǎng)絡(luò)優(yōu)化,惠民網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
在go語(yǔ)言中,控制反轉(zhuǎn)(IoC)是面向?qū)ο缶幊讨械囊环N設(shè)計(jì)原則,可以用來(lái)減低計(jì)算機(jī)代碼之間的耦合度,就是代碼控制權(quán)從業(yè)務(wù)代碼“反轉(zhuǎn)”到框架代碼。常見(jiàn)的控制反轉(zhuǎn)方式叫做依賴注入,還有一種方式叫“依賴查找”;通過(guò)控制反轉(zhuǎn),對(duì)象在被創(chuàng)建的時(shí)候,由一個(gè)調(diào)控系統(tǒng)內(nèi)所有對(duì)象的外界實(shí)體將其所依賴的對(duì)象的引用傳遞給它。
控制反轉(zhuǎn)(Inversion of Control,縮寫為IoC),是面向?qū)ο缶幊讨械囊环N設(shè)計(jì)原則,可以用來(lái)減低計(jì)算機(jī)代碼之間的耦合度。其中最常見(jiàn)的方式叫做依賴注入(Dependency Injection,簡(jiǎn)稱DI),還有一種方式叫“依賴查找”(Dependency Lookup)。通過(guò)控制反轉(zhuǎn),對(duì)象在被創(chuàng)建的時(shí)候,由一個(gè)調(diào)控系統(tǒng)內(nèi)所有對(duì)象的外界實(shí)體將其所依賴的對(duì)象的引用傳遞給它。也可以說(shuō),依賴被注入到對(duì)象中。
講得通俗一點(diǎn),假如我有一個(gè)控制器,UserController,它可以Code,Read,Eat ,當(dāng)然它還有隱式的__construct構(gòu)造函數(shù),__destruct析構(gòu)函數(shù),我們知道這些默認(rèn)函數(shù)在特定的情景會(huì)自己觸發(fā),比如初始化的時(shí)候,生命周期結(jié)束釋放資源的時(shí)候,但是我們?nèi)绻偃邕@些函數(shù)本身都不會(huì)自己觸發(fā),那么我們作為作者怎么去讓他執(zhí)行。實(shí)際上我的控制器還有ArticleController ,YouBadBadController,我怎么去處理。
各干各的 User你干活之前先去構(gòu)建一下自己,Article你干活之前也去構(gòu)建一下自己 這個(gè)情況短板就很明顯了,后面介紹,每個(gè)控制器都要去各干各的,實(shí)際上都是Controller ,在處理公共行為的時(shí)候,其實(shí)我們可以借組外部實(shí)現(xiàn)和管理。 我們不用默認(rèn)的魔法函數(shù)了,介紹一個(gè)具體場(chǎng)景,假如我現(xiàn)在需要每個(gè)控制器都要實(shí)現(xiàn)并調(diào)用一個(gè)handle函數(shù)。我們?cè)趺春侠砣ネ瓿桑偃绗F(xiàn)在還要執(zhí)行一個(gè)run 方法 ,每個(gè)控制器添加完run函數(shù)之后,我們是不是還要寫他們的調(diào)度;
控制反轉(zhuǎn)統(tǒng)一管理 這個(gè)操作是不是可以讓一個(gè)公共的ControllerService幫忙handle就行了,我們現(xiàn)在不考慮繼承。
class ControllerService{
public functiondo(){
->handle();
} //去吧比卡丘; }
}
等等,小智不投精靈球怎么去吧,小智呢? 我們需要把控制方帶過(guò)來(lái)
class ControllerService{
public $handler;
public function __construct($handler){
$this->handler=$handler ;
} //通過(guò)構(gòu)造函數(shù)帶入; }
//
public function setHandler($handler){
$this->handler->handle();
} //通過(guò)setter帶入; }
public function do(){
$this->handler->handle();
} //去吧比卡丘; }
}
new ControllerService()->setHandler(new UserController())->do();
這樣控制權(quán)已經(jīng)反轉(zhuǎn)給ControllerService了;
Go語(yǔ)言中的interface 反射機(jī)制也是Ioc的體現(xiàn)
設(shè)計(jì)
采用的第三方庫(kù)
使用起來(lái)還是比較簡(jiǎn)單的,無(wú)非就是RegisterTo, Invoke,但是任何的庫(kù)都需要結(jié)合框架起來(lái)才有意義。
一提到松耦合,在GO中很容易就想到接口(interface),所以我們用接口實(shí)現(xiàn)的各個(gè)層之間的松耦合。
按照傳統(tǒng)的MVC框架,一般服務(wù)端會(huì)有幾種分層,Controler層、Service層、Module層 從上到下,如何將Ioc結(jié)合在框架中才是值得探討的事情。
調(diào)用結(jié)構(gòu):由于沒(méi)有服務(wù),main函數(shù)充當(dāng)?shù)氖荂ontroler、Service是服務(wù)層、Module是數(shù)據(jù)層、Resource是存儲(chǔ)層、app是各種接口的定義
main-->Service-->Module-->Resource
為了演示服務(wù)之間的調(diào)用,我們定義了service1和service2兩種服務(wù)
實(shí)現(xiàn)
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)
}
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)
}
這里其實(shí)怎么實(shí)現(xiàn)都行,只是一個(gè)單例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 靜態(tài)斷言類型檢測(cè)
func(t app.Resource) {}(mo)
app.GetOrCreateRootContainer().RegisterTo(mo, (*app.Resource)(nil), ioc.Singleton)
//rd := &ResourceObj{name: "redis"} 實(shí)現(xiàn)是用的map,所以mong會(huì)被覆蓋
//app.GetOrCreateRootContainer().RegisterTo(rd, (*app.Resource)(nil), ioc.Singleton)
}
RegisterTo是注冊(cè)過(guò)程,在mo對(duì)象后續(xù)會(huì)當(dāng)作app.Resource接口的實(shí)現(xiàn)來(lái)使用,其底層實(shí)現(xiàn)是一個(gè)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 靜態(tài)斷言類型檢測(cè)
func(t app.Module) {}(mo)
app.GetOrCreateRootContainer().RegisterTo(mo, (*app.Module)(nil), ioc.Singleton)
app.GetOrCreateRootContainer().Invoke(func(r app.Resource) {
rs = r
})
}
因?yàn)槲覀冎癮pp.Resource已經(jīng)注冊(cè)過(guò),所以這里Invoke的時(shí)候就可以獲取到實(shí)現(xiàn)該接口的對(duì)象
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 靜態(tài)斷言做類型檢查
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
})
}
package 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")
}
思考
我們?yōu)槭裁匆玫絀oc呢?個(gè)人感覺(jué)有幾點(diǎn)好處
1.解決各種依賴問(wèn)題,寫GO可能都遇到過(guò)循環(huán)引用問(wèn)題,越是復(fù)雜的系統(tǒng)就越有可能出現(xiàn)這種混亂的調(diào)用現(xiàn)象。
2.實(shí)現(xiàn)了很好的擴(kuò)展性,如果存儲(chǔ)層想從redis切換到mongo,定義一個(gè)相同的對(duì)象,替換注冊(cè)對(duì)象就可以輕松實(shí)現(xiàn)。
3.易使用,隨時(shí)隨地可以通過(guò)Invoke獲取相應(yīng)的接口對(duì)象。
問(wèn)題
難道就沒(méi)有問(wèn)題嗎?
當(dāng)然有,就是引用順序的問(wèn)題,也就是先register 還是先invoke 這個(gè)在例子中感覺(jué)很簡(jiǎn)單,但是在工程中很容易出錯(cuò)
_ "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"
第一種寫法就會(huì)崩潰,第二種正確
原因第一種module 的init 先執(zhí)行,app.Resource的對(duì)象還沒(méi)有注冊(cè)。所以init的先后順序很重要
但這個(gè)是憑借字節(jié)碼進(jìn)行的排序,有時(shí)IDE還不讓我們改,所以需要一些控制器去處理這種情況。
關(guān)于“go語(yǔ)言控制反轉(zhuǎn)指的是什么”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對(duì)“go語(yǔ)言控制反轉(zhuǎn)指的是什么”知識(shí)都有一定的了解,大家如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。