架構(gòu)學(xué)習(xí)之路(三)-- IOC

參考:
https://studygolang.com/articles/13783?fr=sidebar
https://studygolang.com/articles/7716
先寫(xiě)著,我現(xiàn)在吃不透原理
一、IOC
Ioc的思想就是解耦,只依賴容器而不依賴具體的類(lèi),當(dāng)你的類(lèi)有修改時(shí),最多需要改動(dòng)一下容器相關(guān)代碼,業(yè)務(wù)代碼并不受影響。
主要原理通俗來(lái)講就是根據(jù)給出的類(lèi)名(字符串方式)來(lái)動(dòng)態(tài)地生成對(duì)象,這種編程方式可以讓對(duì)象在生成時(shí)才決定到底是哪一種對(duì)象。
我們可以把IOC容器的工作模式看做是工廠模式的升華,可以把IOC容器看作是一個(gè)工廠,這個(gè)工廠里要生產(chǎn)的對(duì)象都在配置文件中給出定義,然后利用編程語(yǔ)言的的反射編程,根據(jù)配置文件中給出的類(lèi)名生成相應(yīng)的對(duì)象。從實(shí)現(xiàn)來(lái)看,IOC是把以前在工廠方法里寫(xiě)死的對(duì)象生成代碼,改變?yōu)橛膳渲梦募?lái)定義,也就是把工廠和對(duì)象生成這兩者獨(dú)立分隔開(kāi)來(lái),目的就是提高靈活性和可維護(hù)性。

golang的依賴注入原理

步驟如下:(golang不支持動(dòng)態(tài)創(chuàng)建對(duì)象,所以需要先手動(dòng)創(chuàng)建對(duì)象然后注入,java可以直接動(dòng)態(tài)創(chuàng)建對(duì)象)

1.通過(guò)反射讀取對(duì)象的依賴(golang是通過(guò)tag實(shí)現(xiàn))
2.在容器中查找有無(wú)該對(duì)象實(shí)例
3.如果有該對(duì)象實(shí)例或者創(chuàng)建對(duì)象的工廠方法,則注入對(duì)象或使用工廠創(chuàng)建對(duì)象并注入
4.如果無(wú)該對(duì)象實(shí)例,則報(bào)錯(cuò)

代碼實(shí)現(xiàn)
package di

import (
    "sync"
    "reflect"
    "fmt"
    "strings"
    "errors"
)

var (
    ErrFactoryNotFound = errors.New("factory not found")
)

type factory = func() (interface{}, error)
// 容器
type Container struct {
    sync.Mutex
    singletons map[string]interface{}
    factories  map[string]factory
}
// 容器實(shí)例化
func NewContainer() *Container {
    return &Container{
        singletons: make(map[string]interface{}),
        factories:  make(map[string]factory),
    }
}

// 注冊(cè)單例對(duì)象
func (p *Container) SetSingleton(name string, singleton interface{}) {
    p.Lock()
    p.singletons[name] = singleton
    p.Unlock()
}

// 獲取單例對(duì)象
func (p *Container) GetSingleton(name string) interface{} {
    return p.singletons[name]
}

// 獲取實(shí)例對(duì)象
func (p *Container) GetPrototype(name string) (interface{}, error) {
    factory, ok := p.factories[name]
    if !ok {
        return nil, ErrFactoryNotFound
    }
    return factory()
}

// 設(shè)置實(shí)例對(duì)象工廠
func (p *Container) SetPrototype(name string, factory factory) {
    p.Lock()
    p.factories[name] = factory
    p.Unlock()
}

// 注入依賴
func (p *Container) Ensure(instance interface{}) error {
    elemType := reflect.TypeOf(instance).Elem()
    ele := reflect.ValueOf(instance).Elem()
    for i := 0; i < elemType.NumField(); i++ { // 遍歷字段
        fieldType := elemType.Field(i)
        tag := fieldType.Tag.Get("di") // 獲取tag
        diName := p.injectName(tag)
        if diName == "" {
            continue
        }
        var (
            diInstance interface{}
            err        error
        )
        if p.isSingleton(tag) {
            diInstance = p.GetSingleton(diName)
        }
        if p.isPrototype(tag) {
            diInstance, err = p.GetPrototype(diName)
        }
        if err != nil {
            return err
        }
        if diInstance == nil {
            return errors.New(diName + " dependency not found")
        }
        ele.Field(i).Set(reflect.ValueOf(diInstance))
    }
    return nil
}

// 獲取需要注入的依賴名稱
func (p *Container) injectName(tag string) string {
    tags := strings.Split(tag, ",")
    if len(tags) == 0 {
        return ""
    }
    return tags[0]
}

// 檢測(cè)是否單例依賴
func (p *Container) isSingleton(tag string) bool {
    tags := strings.Split(tag, ",")
    for _, name := range tags {
        if name == "prototype" {
            return false
        }
    }
    return true
}

// 檢測(cè)是否實(shí)例依賴
func (p *Container) isPrototype(tag string) bool {
    tags := strings.Split(tag, ",")
    for _, name := range tags {
        if name == "prototype" {
            return true
        }
    }
    return false
}

// 打印容器內(nèi)部實(shí)例
func (p *Container) String() string {
    lines := make([]string, 0, len(p.singletons)+len(p.factories)+2)
    lines = append(lines, "singletons:")
    for name, item := range p.singletons {
        line := fmt.Sprintf("  %s: %x %s", name, &item, reflect.TypeOf(item).String())
        lines = append(lines, line)
    }
    lines = append(lines, "factories:")
    for name, item := range p.factories {
        line := fmt.Sprintf("  %s: %x %s", name, &item, reflect.TypeOf(item).String())
        lines = append(lines, line)
    }
    return strings.Join(lines, "\n")
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1.1 spring IoC容器和beans的簡(jiǎn)介 Spring 框架的最核心基礎(chǔ)的功能是IoC(控制反轉(zhuǎn))容器,...
    simoscode閱讀 6,846評(píng)論 2 22
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 34,627評(píng)論 18 399
  • 2.1 我們的理念是:讓別人為你服務(wù) IoC是隨著近年來(lái)輕量級(jí)容器(Lightweight Container)的...
    好好學(xué)習(xí)Sun閱讀 2,862評(píng)論 0 11
  • 又到了一個(gè)周末,照例睡到中午才起床,然后看《微微一笑很傾城》的電視劇,然后在pad上玩了一會(huì)兒游戲,之后把宜家買(mǎi)回...
    Ms_Y_楊小姐閱讀 396評(píng)論 0 0
  • TIME : 2018-05-17 sklearn.naive_bayes.BernoulliNB 與多項(xiàng)式模型一...
    niartnelis閱讀 3,477評(píng)論 0 2

友情鏈接更多精彩內(nèi)容