基于IOC解决对象依赖问题

ioc是一种软件设计原则,用来降低代码之间耦合度。如果没有ioc机制,多个模块调用会显得异常繁琐,而ioc是将控制权从程序代码中抽离,交给外部的容器或框架,从而实现依赖关系的动态置顶,增加程序的灵活性和可维护性,下面我的例子只是一个简单的以容器为基础实现的ioc注册。

store.go:

  • IocContainer:负责注册ioc对象、初始化ioc对象操作
ackage ioc

import (
    "fmt"
    "gitee.com/dujie5416/vblog/apps/users/config"
    "github.com/gin-gonic/gin"
)

//
//  IocContainer
//  @Description: 定义一个对象注册表
//
type IocContainer struct {
    // 采用map来保证对象的注册关系
    store map[string]IocObject
}

/*
 * Init
 * @Description: 负责初始化所有的对象,因为map是无序的,这里如果要控制初始化的顺序,可以替换成list
 * @receiver c
 * @return error
 */
func (c *IocContainer) Init() error {
    fmt.Println(c.store)
    config.LoadMysqlConfigFromToml("../etc/mysql.toml")
    // 遍历所有单例对象,并对每个单例对象进行初始化操作
    for _, obj := range c.store {
        if err := obj.Init(); err != nil {
            return err
        }
    }
    return nil
}

/*
 * Registry
 * @Description: 将对象注册到ioc中
 * @receiver c
 * @param obj
 */
func (c *IocContainer) Registry(obj IocObject) {
    c.store[obj.Name()] = obj
}

/*
 * Get
 * @Description: 获取ioc对象的名字
 * @receiver c
 * @param name
 * @return any
 */
func (c *IocContainer) Get(name string) any {
    return c.store[name]
}

//
//  GinApiHandlers
//  @Description: gin api的接口,用于注册路由
//
type GinApiHandlers interface {
    RegisterRouter(r gin.IRouter)
}

/*
 * RouteRegistry
 * @Description: 将每个api handlers 的路由注册到root router中
 * @receiver c
 * @param router
 */
func (c *IocContainer) RouteRegistry(router gin.IRouter) {
    fmt.Println(c.store)
    // 找到被扩管的APIHandler
    for _, obj := range c.store {
        if api, ok := obj.(GinApiHandlers); ok {
            api.RegisterRouter(router)
        }
    }
}

interface.go:定义Init()和Name()函数,注册进ioc对象必须实现该两种方法

package ioc

//
//  IocObject
//  @Description: 定义注册进来的对象的约束条件
//
type IocObject interface {
    // 对象的初始化
    Init() error
    // 对象的名称
    Name() string
}

controller.go:专门用于注入controller对象

package ioc

/*
 * Controller
 * @Description: 专门用于注册controller对象
 * @return *IocContainer
 */
func Controller() *IocContainer {
    return controllerContainer
}

//ioc注册表对象,全局只有一个
var controllerContainer = &IocContainer{
    store: map[string]IocObject{},
}

api.go:专门注册api对象

package ioc

import "fmt"

/*
 * ApiHandler
 * @Description: 专门用于注册api handler对象
 * @return *IocContainer
 */
func ApiHandler() *IocContainer {
    return apiHandlerContainer
}

//ioc注册表对象,全局只有一个
var apiHandlerContainer = &IocContainer{
    store: map[string]IocObject{},
}

func init() {
    fmt.Println("这是apihand")
}

将对象注入到ioc:

package impl

import (
    "gitee.com/dujie5416/vblog/apps/blog"
    "gitee.com/dujie5416/vblog/apps/users/config"
    "gitee.com/dujie5416/vblog/ioc"
    "gorm.io/gorm"
)

/*
 * init
 * @Description: 将blog impl 对象注册到ioc管理
 */
func init() {
    ioc.Controller().Registry(&BlogImpl{})
}

//
//  BlogImpl
//  @Description: 博客实现结构体
//
type BlogImpl struct {
    db *gorm.DB
}

/*
 * Init
 * @Description: 实现ioc obj 接口
 * @receiver b
 * @return error
 */
func (b *BlogImpl) Init() error {
    b.db = config.C().Mysql.GetMysqlConnect()
    return nil
}
func (b *BlogImpl) Name() string {
    return blog.AppName
}

根据name获取ioc对象的值:

package api

import (
    "gitee.com/dujie5416/vblog/apps/blog"
    "gitee.com/dujie5416/vblog/ioc"
)

func init() {
    ioc.ApiHandler().Registry(&BlogApiHandler{})
}

type BlogApiHandler struct {
    svc blog.Service
}

func (b *BlogApiHandler) Init() error {
    b.svc = ioc.Controller().Get(blog.AppName).(blog.Service)
    return nil
}
func (b *BlogApiHandler) Name() string {
    return blog.AppName
}