Home > Backend Development > Golang > What is inversion of control in go language

What is inversion of control in go language

青灯夜游
Release: 2023-01-28 11:12:00
Original
2033 people have browsed it

In the Go language, Inversion of Control (IoC) is a design principle in object-oriented programming. It can be used to reduce the coupling between computer codes, that is, the code control is "reversed" from the business code. ” to the framework code. A common method of inversion of control is called dependency injection, and another method is called "dependency lookup"; through inversion of control, when an object is created, an external entity that controls all objects in the system references the objects it depends on. pass it.

What is inversion of control in go language

The operating environment of this tutorial: Windows 7 system, GO version 1.18, Dell G3 computer.

What is Inversion of Control

Inversion of Control (Inversion of Control, abbreviated as IoC) is a design principle in object-oriented programming that can be used Reduce coupling between computer codes. The most common method is called Dependency Injection (DI), and the other method is called Dependency Lookup. Through inversion of control, when an object is created, an external entity that controls all objects in the system passes the reference of the object it depends on to it. It can also be said that dependencies are injected into the object.

To put it more simply, if I have a controller, UserController, it can Code, Read, and Eat. Of course, it also has implicit __construct constructor and __destruct destructor. We know these default functions. It will trigger itself in certain situations, such as initialization, when resources are released at the end of the life cycle, but if we assume that these functions themselves will not trigger themselves, then how can we, as authors, let them execute. In fact, my controller also has ArticleController and YouBadBadController. How should I handle it?

Each user should build himself before working. Article should also build himself before working. The shortcomings of this situation are obvious. As will be introduced later, each controller must be built. Everyone does their own thing, but they are actually all Controllers. When dealing with public behaviors, we can actually implement and manage them externally. We don't need the default magic function. Let's introduce a specific scenario. Suppose I now need each controller to implement and call a handle function. How can we complete it reasonably? If we still need to execute a run method now, after adding the run function to each controller, do we still need to write their schedule?

Is inversion of control a unified management of this operation? You can just let a public ControllerService help handle it. We are not considering inheritance now.

class ControllerService{

public functiondo(){

->handle();

 } //去吧比卡丘; }

}
Copy after login

Wait a minute, how can Xiaozhi go without throwing a Poké Ball? Where is Xiaozhi? We need to bring the controller over

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();
Copy after login

so that the control has been reversed to ControllerService;

The interface reflection mechanism in Go language is also the embodiment of Ioc

Golang Inversion of Control (IOC) is applied in the project

Design

The third-party library used:https: //github.com/berkaroad/ioc

It is relatively simple to use, nothing more than RegisterTo and Invoke, but any library needs to be combined with a framework to be meaningful.

When it comes to loose coupling, it is easy to think of interface(interface) in GO, so we use interfaces to achieve loose coupling between various layers.

According to the traditional MVC framework, there are generally several layers on the server side, Controller layer, Service layer, and Module layer. From top to bottom, how to combine Ioc in the framework is something worth exploring.

Directory

What is inversion of control in go language

Calling structure: Since there is no service, the main function acts as the Controller, Service is the service layer, and Module is the data Layer, Resource is the storage layer, and app is the definition of various interfaces
main-->Service-->Module-->Resource
In order to demonstrate the calls between services, we defined service1 and service2 Two services

implementation

Interface definition of each layer

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)
}
Copy after login

IOC Initialization

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)
}
Copy after login

In fact, no matter how you implement it, it is just a single instance NewContainer

Storage layer (bottom-up)

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)
}
Copy after login

RegisterTo is the registration process. The mo object will be used as the implementation of the app.Resource interface later. Its underlying implementation is a map

data layer

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
	})
}
Copy after login

Because we have already registered app.Resource before, we can get the object that implements this interface when Invoke here

Service layer

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
	})
}
Copy after login

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")
}
Copy after login

Test

What is inversion of control in go language

##Thoughts

我们为什么要用到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"
Copy after login
        _ "github.com/zhaoshoucheng/hodgepodge/IoC/resource"
	_ "github.com/zhaoshoucheng/hodgepodge/IoC/module"
	_ "github.com/zhaoshoucheng/hodgepodge/IoC/service"
Copy after login

第一种写法就会崩溃,第二种正确

原因第一种module 的init 先执行,app.Resource的对象还没有注册。所以init的先后顺序很重要

但这个是凭借字节码进行的排序,有时IDE还不让我们改,所以需要一些控制器去处理这种情况。

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

The above is the detailed content of What is inversion of control in go language. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template