Go 언어에서 DI(종속성 주입)는 필요할 때 구성 요소 간의 종속성을 분리하는 디자인 패턴입니다. 서로 다른 구성 요소는 통합 인터페이스를 통해 다른 구성 요소의 객체와 상태를 얻을 수 있습니다. 종속성 주입의 이점은 분리이며, 분리는 향상된 코드 확장성, 향상된 코드 유지 관리, 보다 쉬운 단위 테스트 등 더 많은 이점을 가져올 수 있습니다.
이 튜토리얼의 운영 환경: Windows 7 시스템, GO 버전 1.18, Dell G3 컴퓨터.
이 단어를 처음 들었을 때 발음하기가 어려웠습니다. 아마도 봄철을 공부한 많은 학생들이 이것이 매우 기본적이고 이해하기 쉬운 지식이라고 생각하지만, 저는 이 단어를 한번도 배운 적이 없기 때문입니다. Java와 Spring이라 처음 이 단어를 접했을 때 매우 혼란스러웠습니다.
Dependency Injection, 영어 이름은 의존성 주입, 줄여서 DI입니다. 종속성이라는 단어는 이해하기 쉽습니다. 소프트웨어 설계에는 아키텍처 모듈에서 기능적 방법에 이르기까지 크고 작은 종속성이 있습니다.
예를 들어, 새로운 A보다 새로운 B가 생성되어야 하고, A는 B에 종속됩니다. 이때 B는 A의 종속성이고, A는 B를 제어하며, AB와 B 사이에는 결합 관계가 있다고 말할 수 있습니다. 코드 디자인 아이디어는 최고의 느슨한 결합을 달성할 수 있습니다. 어느 날 B를 변환해야 한다면 A도 변환해야 합니다. 이것이 종속성이라면 문제가 없을 수 있지만 A->B->C->D->E->F 사이에 일련의 종속성이 있는 경우 변환하는 것이 매우 번거로울 것입니다.
이때, 그들 사이의 강력한 결합을 분리할 무언가가 필요합니다. 어떻게 분리할 수 있을까요? 우리는 A에서 B까지의 통제권을 제3자에게 넘겨줄 수 밖에 없습니다. 이런 아이디어를 Inversion of Control(IOC Inversion Of Control)이라고 하며, 이 제3자를 IOC 컨테이너라고 합니다. IOC 컨테이너가 해야 할 일은 새로운 B를 생성한 다음 이 B의 인스턴스를 A에 주입하는 것입니다. 그러면 A는 일반적으로 B 기반 메서드를 사용할 수 있습니다. 이 프로세스를 종속성 주입이라고 하며 IOC 기반 이 메서드를 호출합니다. 의존성 주입.
간단히 말하면 DI(종속성 주입)는 구성 요소 간의 종속성을 분리하는 디자인 패턴입니다. 필요한 경우 다양한 구성 요소가 통합 인터페이스를 통해 다른 구성 요소의 개체와 상태를 얻을 수 있습니다. Go 언어의 인터페이스 디자인은 타사 종속성 주입 프레임워크(예: Java 등)를 사용해야 하는 많은 상황을 방지합니다. 우리의 주입 솔루션은 Dager 또는 Guice와 유사한 주입 솔루션을 거의 제공하지 않으며 개체와 구성 요소 간의 종속성을 수동으로 구성하지 않는 데 중점을 둡니다.
의존성 주입의 개념을 이해하려면 이것이 가져오는 가장 큰 이점인 디커플링도 이해해야 합니다.
그리고 분리는 향상된 코드 확장성, 향상된 코드 유지 관리, 보다 쉬운 단위 테스트 등 더 많은 이점을 가져올 수 있습니다.
그럼 종속성 주입을 구현하는 방법은 무엇입니까?
Java에는 다음과 같은 메소드가 있습니다.
setter 메소드 주입: 외부 컨테이너가 종속 유형의 객체를 호출할 수 있도록 특정 속성의 공개 설정 메소드를 구현합니다.
인터페이스 기반 주입: 종속 유형의 개체를 주입하기 위해 외부 컨테이너에 대한 특정 인터페이스를 구현합니다.
생성자 기반 주입: 특정 매개변수로 생성자를 구현하고 새 객체를 생성할 때 종속 유형의 객체를 전달합니다.
주석 기반 주입: 코드에 특정 키워드를 추가하여 주입을 수행합니다.
주석은 주석과 마찬가지로 코드로 실행되지 않고 특별히 다른 사람들이 읽을 수 있도록 하는 가장 일반적인 방법입니다. 그러나 주석을 읽는 사람은 전적으로 사람이고, 사람 이외의 주석을 읽는 주요 독자는 프레임워크나 프리컴파일러입니다.
wire는 주석 기반 의존성 주입 방법입니다. wire
는 Google의 오픈 소스 종속성 주입 도구로, 특수 go
파일에서 유형 간의 종속성을 wire
에 알려 주기만 하면 됩니다. 자동으로 코드를 생성하고, 지정된 유형의 객체를 생성하고, 해당 종속성을 조합하는 데 도움을 줍니다. wire
是 Google 开源的一个依赖注入工具,我们只需要在一个特殊的go
文件中告诉wire
类型之间的依赖关系,它会自动帮我们生成代码,帮助我们创建指定类型的对象,并组装它的依赖。
wire
有两个基础概念,Provider
(构造器)和Injector
(注入器)。
通过提供provider
函数,让wire
知道如何产生这些依赖对象。wire
根据我们定义的injector
函数签名,生成完整的injector
函数,injector
函数是最终我们需要的函数,它将按依赖顺序调用provider
。
wire
的要求很简单,新建一个wire.go
文件(文件名可以随意),创建我们的初始化函数。比如,我们要创建并初始化一个Mission
wire
에는 Provider
(생성자)와 Injector
(인젝터)라는 두 가지 기본 개념이 있습니다. 🎜🎜 provider
기능을 제공하여 wire
에 이러한 종속 개체를 생성하는 방법을 알립니다. wire
는 우리가 정의한 injector
함수 서명을 기반으로 완전한 injector
함수를 생성합니다. need. 의존성 순서에 따라 provider
를 호출하는 함수입니다. 🎜🎜wire
에 대한 요구 사항은 매우 간단합니다. 새 wire.go
파일(파일 이름은 임의적일 수 있음)을 만들고 초기화 기능을 만듭니다. 예를 들어 Mission
객체를 생성하고 초기화하려는 경우 다음과 같이 할 수 있습니다. 🎜//+build wireinject package main import "github.com/google/wire" func InitMission(name string) Mission { wire.Build(NewMonster, NewPlayer, NewMission) return Mission{} }
첫 번째 줄에서 +build wireinject라는 주석을 볼 수 있는데, 이는 이것이 인젝터임을 나타냅니다. +build
는 실제로 Go 언어의 기능입니다. C/C++의 조건부 컴파일과 마찬가지로 go build
실행 시 일부 옵션을 전달할 수 있으며, 이러한 옵션에 따라 특정 파일의 컴파일 여부가 결정됩니다. wire
도구는 wireinject
를 사용하는 파일만 처리하므로 wire.go
파일에 이를 추가해야 합니다. +build
其实是 Go 语言的一个特性。类似 C/C++ 的条件编译,在执行go build
时可传入一些选项,根据这个选项决定某些文件是否编译。wire
工具只会处理有wireinject
的文件,所以我们的wire.go
文件要加上这个。
在函数中,我们调用wire.Build()
将创建Mission
所依赖的类型的构造器传进去。例如,需要调用NewMission()
创建Mission
类型,NewMission()
接受两个参数一个Monster
类型,一个Player
类型。Monster
类型对象需要调用NewMonster()
创建,Player
类型对象需要调用NewPlayer()
创建。所以NewMonster()
和NewPlayer()
我们也需要传给wire
wire.Build()
를 호출하여 Mission
이 의존하는 유형의 생성자를 전달합니다. 예를 들어, Mission
유형을 생성하려면 NewMission()
을 호출해야 합니다. NewMission()
은 두 개의 매개변수와 Monster 유형입니다. <code>Monster
유형의 객체는 NewMonster()
를 호출하여 생성해야 하고, Player
유형의 객체는 NewPlayer()를 호출하여 생성해야 합니다.
. 따라서 NewMonster()
및 NewPlayer()
도 wire
에 전달해야 합니다. wire.go 파일을 작성하고 wire 명령어를 실행하면 wire_gen.go 파일이 자동으로 생성됩니다. // Code generated by Wire. DO NOT EDIT. //go:generate wire //+build !wireinject package main // Injectors from wire.go: func InitMission(name string) Mission { player := NewPlayer(name) monster := NewMonster() mission := NewMission(player, monster) return mission }와이어가 자동으로 InitMission 메서드를 생성하는 것을 볼 수 있습니다. 이 메서드에서는 플레이어, 몬스터, 미션이 순차적으로 초기화됩니다. 그런 다음 주 함수에서 이 InitMission만 호출하면 됩니다.
func main() { mission := InitMission("dj") mission.Start() }종속성 주입 이전의 코드는 다음과 같았습니다.
func main() { monster := NewMonster() player := NewPlayer("dj") mission := NewMission(player, monster) mission.Start() }훨씬 더 간단하지 않나요? 여기에는 개체 초기화가 세 개만 있습니다. 그 이상이면 종속성 주입의 이점을 깨닫지 못할 수도 있습니다. 예:
wire.go文件: // +build wireinject // The build tag makes sure the stub is not built in the final build. package di import ( "github.com/google/wire" ) //go:generate kratos t wire func InitApp() (*App, func(), error) { panic(wire.Build(dao.Provider, service.Provider, http.New, grpc.New, NewApp)) } 实现文件: //dao var Provider = wire.NewSet(New, NewDB, NewRedis) //service var Provider = wire.NewSet(New, wire.Bind(new(pb.Server), new(*Service))) 生成的wire_gen.go 文件: func InitApp() (*App, func(), error) { redis, cleanup, err := dao.NewRedis() if err != nil { return nil, nil, err } db, cleanup2, err := dao.NewDB() if err != nil { cleanup() return nil, nil, err } daoDao, cleanup3, err := dao.New(redis, db) if err != nil { cleanup2() cleanup() return nil, nil, err } serviceService, cleanup4, err := service.New(daoDao) if err != nil { cleanup3() cleanup2() cleanup() return nil, nil, err } engine, err := http.New(serviceService) if err != nil { cleanup4() cleanup3() cleanup2() cleanup() return nil, nil, err } server, err := grpc.New(serviceService) if err != nil { cleanup4() cleanup3() cleanup2() cleanup() return nil, nil, err } app, cleanup5, err := NewApp(serviceService, engine, server) if err != nil { cleanup4() cleanup3() cleanup2() cleanup() return nil, nil, err } return app, func() { cleanup5() cleanup4() cleanup3() cleanup2() cleanup() }, nil }그렇다면 종속성 주입이란 정확히 무엇입니까? 그냥 캡슐화와 디커플링일 뿐입니다. 】🎜
위 내용은 Go 언어 의존성 주입이란 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!