首页 > 其他分享 >go语言的控制反转 (IOC)在工程中应用

go语言的控制反转 (IOC)在工程中应用

时间:2022-12-29 18:57:05浏览次数:64  
标签:github func 反转 app com str go IOC string

背景

最近在总结现有框架中一些比较有亮点的地方,个人觉得带着问题去学习是比较高效的事情,所以把一些学习总结记录下来。
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)
}

存储层(自下而上)

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

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

测试

思考

我们为什么要用到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还不让我们改,所以需要一些控制器去处理这种情况,
可以看下篇的应用程序生命周期控制器去解决这个问题

本次代码:https://github.com/zhaoshoucheng/hodgepodge/tree/main/IoC

标签:github,func,反转,app,com,str,go,IOC,string
From: https://www.cnblogs.com/zhaosc-haha/p/17013239.html

相关文章

  • 将链表进行反转
    1:在完成这道题之前有两个方法去完成,一个是递归。一个非递归。殊途同归都是反转相邻的两个节点递归的方法:classSolution{public:ListNode*reverse(ListNode*......
  • docker安装mongodb
    dockerrun-d\--namemongodb\--restartalways\--privileged\-p27017:27017\-v/data/mongodb/data:/data/db\-eMONGO_INITDB_ROOT_USERNAME......
  • Go-21 Golang接口详解
    packagemainimport"fmt"//Golang中的接口详解/* 1.接口的介绍 2.Golang接口的定义 3.空接口 4.类型断言 5.结构体值接收者和指针接收者实现接口的区别 6.一......
  • go语言知识点
    1.可以定义变量而不初始化,则变量默认零值(0/false/""),如vara;intfmt.Println(a)2.可以不指定变量类型,则系统根据变量的初始值判断变量类型。如vara=true3.变量作......
  • golang中使用原子操作监听配置更新
    配置及代码文件{"name":"sasuke","age":25,"gender":"male","score":99.5}develop.jsonpackagemainimport("crypto/md5""enco......
  • Google SEM和谷歌SEO的区别
    很多人对GoogleSEM和GoogleSEO概念很模糊。米贸搜整理如下。看图:GoogleSEM和SEO的关系在上图中,最上面的部分属于GoogleSEM,即GoogleAds广告推广,是一种按效果付费的广告......
  • Go - 高并发抢到红包实现
    //utils.gopackagemainimport("fmt""math/rand""sync""time")//抢红包任务结构体typetaskstruct{iduint32//表示红包idcallbackcha......
  • Django开发必备的10个第三方库
    以下的这几个第三方库,常用于Django开发中1.django-import-export:导入导出数据2.django-filter:过滤数据使用3.django-restframework:restful-Api使用4.pymysql:......
  • 1.Django安装和运行
    一、安装DjangoDjango框架是用Python语言开发的,只需要执行命令pipinstalldjango验证:python-mdjango--version>4.1.4切换到项目文件下,执行命令djang......
  • Go并发
    packagemainimport("fmt""runtime""sync""time")varcintfunccounter()int{c++returnc}funcmain2(){a:=100......