0

0

go语言中控制反转是什么

青灯夜游

青灯夜游

发布时间:2023-01-28 11:12:00

|

2306人浏览过

|

来源于php中文网

原创

在go语言中,控制反转(IoC)是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度,就是代码控制权从业务代码“反转”到框架代码。常见的控制反转方式叫做依赖注入,还有一种方式叫“依赖查找”;通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。

go语言中控制反转是什么

本教程操作环境:windows7系统、GO 1.18版本、Dell G3电脑。

控制反转是什么

控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

讲得通俗一点,假如我有一个控制器,UserController,它可以Code,Read,Eat ,当然它还有隐式的__construct构造函数,__destruct析构函数,我们知道这些默认函数在特定的情景会自己触发,比如初始化的时候,生命周期结束释放资源的时候,但是我们如果假如这些函数本身都不会自己触发,那么我们作为作者怎么去让他执行。实际上我的控制器还有ArticleController ,YouBadBadController,我怎么去处理。

各干各的 User你干活之前先去构建一下自己,Article你干活之前也去构建一下自己 这个情况短板就很明显了,后面介绍,每个控制器都要去各干各的,实际上都是Controller ,在处理公共行为的时候,其实我们可以借组外部实现和管理。 我们不用默认的魔法函数了,介绍一个具体场景,假如我现在需要每个控制器都要实现并调用一个handle函数。我们怎么合理去完成,假如现在还要执行一个run 方法 ,每个控制器添加完run函数之后,我们是不是还要写他们的调度;

立即学习go语言免费学习笔记(深入)”;

控制反转统一管理 这个操作是不是可以让一个公共的ControllerService帮忙handle就行了,我们现在不考虑继承。

class ControllerService{

public functiondo(){

->handle();

 } //去吧比卡丘; }

}

等等,小智不投精灵球怎么去吧,小智呢? 我们需要把控制方带过来

class ControllerService{
public $handler;

public function __construct($handler){

    $this->handler=$handler ;

} //通过构造函数带入; }

//

public function setHandler($handler){

     $this->handler->handle();

 } //通过setter带入; }

public function do(){

     $this->handler->handle();

 } //去吧比卡丘; }

}

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

这样控制权已经反转给ControllerService了;

Go语言中的interface 反射机制也是Ioc的体现

Golang 控制反转 (IOC)在工程中应用

设计

采用的第三方库:https://github.com/berkaroad/ioc

使用起来还是比较简单的,无非就是RegisterTo, Invoke,但是任何的库都需要结合框架起来才有意义。

一提到松耦合,在GO中很容易就想到接口(interface),所以我们用接口实现的各个层之间的松耦合。

按照传统的MVC框架,一般服务端会有几种分层,Controler层、Service层、Module层 从上到下,如何将Ioc结合在框架中才是值得探讨的事情。

目录

go语言中控制反转是什么

Python开发网站指南 WORD版
Python开发网站指南 WORD版

本文档主要讲述的是Python开发网站指南;HTML是网络的通用语言,一种简单、通用的全置标记语言。它允许网页制作人建立文本与图片相结合的复杂页面,这些页面可以被网上任何其他人浏览到,无论使用的是什么类型的电脑或浏览器 Python和其他程序语言一样,有自身的一套流程控制语句,而且这些语句的语法和其它程序语言类似,都有for, if ,while 类的关键字来表达程序流程。希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看

下载

调用结构:由于没有服务,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)
}

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

这里其实怎么实现都行,只是一个单例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 静态断言类型检测
	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")
}

测试

go语言中控制反转是什么

思考

我们为什么要用到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还不让我们改,所以需要一些控制器去处理这种情况。

【相关推荐:Go视频教程编程教学

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

178

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

226

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

337

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

208

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

388

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

195

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

190

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

192

2025.06.17

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

36

2026.01.14

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Rust 教程
Rust 教程

共28课时 | 4.4万人学习

Kotlin 教程
Kotlin 教程

共23课时 | 2.5万人学习

Go 教程
Go 教程

共32课时 | 3.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号