溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

go語言控制反轉(zhuǎn)指的是什么

發(fā)布時間:2023-01-31 09:18:11 來源:億速云 閱讀:137 作者:iii 欄目:編程語言

這篇文章主要介紹了go語言控制反轉(zhuǎn)指的是什么的相關(guān)知識,內(nèi)容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇go語言控制反轉(zhuǎn)指的是什么文章都會有所收獲,下面我們一起來看看吧。

在go語言中,控制反轉(zhuǎn)(IoC)是面向?qū)ο缶幊讨械囊环N設(shè)計原則,可以用來減低計算機代碼之間的耦合度,就是代碼控制權(quán)從業(yè)務(wù)代碼“反轉(zhuǎn)”到框架代碼。常見的控制反轉(zhuǎn)方式叫做依賴注入,還有一種方式叫“依賴查找”;通過控制反轉(zhuǎn),對象在被創(chuàng)建的時候,由一個調(diào)控系統(tǒng)內(nèi)所有對象的外界實體將其所依賴的對象的引用傳遞給它。

控制反轉(zhuǎn)是什么

控制反轉(zhuǎn)(Inversion of Control,縮寫為IoC),是面向?qū)ο缶幊讨械囊环N設(shè)計原則,可以用來減低計算機代碼之間的耦合度。其中最常見的方式叫做依賴注入(Dependency Injection,簡稱DI),還有一種方式叫“依賴查找”(Dependency Lookup)。通過控制反轉(zhuǎn),對象在被創(chuàng)建的時候,由一個調(diào)控系統(tǒng)內(nèi)所有對象的外界實體將其所依賴的對象的引用傳遞給它。也可以說,依賴被注入到對象中。

講得通俗一點,假如我有一個控制器,UserController,它可以Code,Read,Eat ,當(dāng)然它還有隱式的__construct構(gòu)造函數(shù),__destruct析構(gòu)函數(shù),我們知道這些默認函數(shù)在特定的情景會自己觸發(fā),比如初始化的時候,生命周期結(jié)束釋放資源的時候,但是我們?nèi)绻偃邕@些函數(shù)本身都不會自己觸發(fā),那么我們作為作者怎么去讓他執(zhí)行。實際上我的控制器還有ArticleController ,YouBadBadController,我怎么去處理。

各干各的 User你干活之前先去構(gòu)建一下自己,Article你干活之前也去構(gòu)建一下自己 這個情況短板就很明顯了,后面介紹,每個控制器都要去各干各的,實際上都是Controller ,在處理公共行為的時候,其實我們可以借組外部實現(xiàn)和管理。 我們不用默認的魔法函數(shù)了,介紹一個具體場景,假如我現(xiàn)在需要每個控制器都要實現(xiàn)并調(diào)用一個handle函數(shù)。我們怎么合理去完成,假如現(xiàn)在還要執(zhí)行一個run 方法 ,每個控制器添加完run函數(shù)之后,我們是不是還要寫他們的調(diào)度;

控制反轉(zhuǎn)統(tǒng)一管理 這個操作是不是可以讓一個公共的ControllerService幫忙handle就行了,我們現(xiàn)在不考慮繼承。

class ControllerService{

public functiondo(){

->handle();

 } //去吧比卡丘; }

}

等等,小智不投精靈球怎么去吧,小智呢? 我們需要把控制方帶過來

class ControllerService{
public $handler;

public function __construct($handler){

    $this->handler=$handler ;

} //通過構(gòu)造函數(shù)帶入; }

//

public function setHandler($handler){

     $this->handler->handle();

 } //通過setter帶入; }

public function do(){

     $this->handler->handle();

 } //去吧比卡丘; }

}

new ControllerService()->setHandler(new UserController())->do();

這樣控制權(quán)已經(jīng)反轉(zhuǎn)給ControllerService了;

Go語言中的interface 反射機制也是Ioc的體現(xiàn)

Golang 控制反轉(zhuǎn) (IOC)在工程中應(yīng)用

設(shè)計

采用的第三方庫

使用起來還是比較簡單的,無非就是RegisterTo, Invoke,但是任何的庫都需要結(jié)合框架起來才有意義。

一提到松耦合,在GO中很容易就想到接口(interface),所以我們用接口實現(xiàn)的各個層之間的松耦合。

按照傳統(tǒng)的MVC框架,一般服務(wù)端會有幾種分層,Controler層、Service層、Module層 從上到下,如何將Ioc結(jié)合在框架中才是值得探討的事情。

目錄

go語言控制反轉(zhuǎn)指的是什么

調(diào)用結(jié)構(gòu):由于沒有服務(wù),main函數(shù)充當(dāng)?shù)氖荂ontroler、Service是服務(wù)層、Module是數(shù)據(jù)層、Resource是存儲層、app是各種接口的定義
main-->Service-->Module-->Resource
為了演示服務(wù)之間的調(diào)用,我們定義了service1和service2兩種服務(wù)

實現(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)
}

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)
}

這里其實怎么實現(xiàn)都行,只是一個單例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)斷言類型檢測
	func(t app.Resource) {}(mo)
	app.GetOrCreateRootContainer().RegisterTo(mo, (*app.Resource)(nil), ioc.Singleton)
        //rd := &ResourceObj{name: "redis"} 實現(xiàn)是用的map,所以mong會被覆蓋
        //app.GetOrCreateRootContainer().RegisterTo(rd, (*app.Resource)(nil), ioc.Singleton)
}

RegisterTo是注冊過程,在mo對象后續(xù)會當(dāng)作app.Resource接口的實現(xiàn)來使用,其底層實現(xiàn)是一個map

數(shù)據(jù)層

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)斷言類型檢測
	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已經(jīng)注冊過,所以這里Invoke的時候就可以獲取到實現(xiàn)該接口的對象

服務(wù)層

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
	})
}

Main

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")
}

測試

go語言控制反轉(zhuǎn)指的是什么

思考

我們?yōu)槭裁匆玫絀oc呢?個人感覺有幾點好處
1.解決各種依賴問題,寫GO可能都遇到過循環(huán)引用問題,越是復(fù)雜的系統(tǒng)就越有可能出現(xiàn)這種混亂的調(diào)用現(xiàn)象。
2.實現(xiàn)了很好的擴展性,如果存儲層想從redis切換到mongo,定義一個相同的對象,替換注冊對象就可以輕松實現(xiàn)。
3.易使用,隨時隨地可以通過Invoke獲取相應(yīng)的接口對象。

問題

難道就沒有問題嗎?
當(dāng)然有,就是引用順序的問題,也就是先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 先執(zhí)行,app.Resource的對象還沒有注冊。所以init的先后順序很重要

但這個是憑借字節(jié)碼進行的排序,有時IDE還不讓我們改,所以需要一些控制器去處理這種情況。

關(guān)于“go語言控制反轉(zhuǎn)指的是什么”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對“go語言控制反轉(zhuǎn)指的是什么”知識都有一定的了解,大家如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI