ホームページ >バックエンド開発 >Golang >Go 言語の依存性注入とは何ですか?

Go 言語の依存性注入とは何ですか?

青灯夜游
青灯夜游オリジナル
2023-01-18 16:41:241851ブラウズ

Go 言語における依存関係注入 (DI) は、コンポーネント間の依存関係を分離する設計パターンであり、必要に応じて、さまざまなコンポーネントが、統一されたインターフェイス (オブジェクトと状態) を通じて他のコンポーネントから情報を取得できます。依存関係注入の利点は分離にあり、分離により、コードのスケーラビリティの強化、コードの保守性の強化、単体テストの容易化など、さらなる利点がもたらされます。

Go 言語の依存性注入とは何ですか?

このチュートリアルの動作環境: Windows 7 システム、GO バージョン 1.18、Dell G3 コンピューター。

#依存性注入とは何ですか?

最初にこの言葉を聞いたとき、私は混乱して発音するのが難しかったです。春を勉強したことがある多くの学生は、これが非常に基本的でわかりやすい知識だと思うかもしれませんが、私は学んだことがないので、 Java か Spring か、最初にこの用語に触れたとき、私は非常に混乱しました。

依存性注入、英語名は依存性注入、略してDIです。依存関係という言葉は理解しやすいですが、ソフトウェア設計では、アーキテクチャモジュールから機能メソッドに至るまで、大小さまざまな依存関係が存在します。

たとえば、新しい A の前に新しい B を作成する必要があります。A は B に依存します。このとき、B は A の依存関係であると言えます。A が B を制御します。AB の間には結合関係があります。 、およびコード設計 疎結合を実現するのが最善であるという考えです。いつか B を変換する必要がある場合、A も変換する必要があります。これが依存関係であれば問題ないかもしれませんが、A->B->C->D->E->F という一連の依存関係がある場合、変換するのが非常に面倒になります。

現時点では、両者の間の強い結合を切り離すために何かが必要です。それを切り離すにはどうすればよいでしょうか? 使用できるのは第三者の力だけです。A を B に当てはめます。制御を第三者に引き渡すという考え方は

Inversion of Control (IOC Inversion Of Control) と呼ばれ、この第三者は IOC コンテナと呼ばれます。 IOC コンテナがしなければならないことは、新しい B を作成し、この B のインスタンスを A に注入することです。その後、A は通常、B に基づいたメソッドを使用できます。このプロセスは依存関係の注入と呼ばれ、IOC に基づいてこのメソッドはと呼ばれます。依存性の注入。

簡単に言うと、依存関係注入 (DI) は、コンポーネント間の依存関係を分離する設計パターンです。必要に応じて、さまざまなコンポーネントが、統一されたインターフェイスを通じて他のコンポーネントのオブジェクトや状態を取得できます。 Go 言語のインターフェイス設計により、サードパーティの依存関係注入フレームワーク (Java など) を使用する必要がある多くの状況が回避されます。当社の注入ソリューションは、Dager や Guice と同様の注入ソリューションをごくわずかしか提供せず、オブジェクトとコンポーネント間の依存関係の手動構成を回避することに重点を置いています。

依存関係注入の利点

依存関係注入の概念を理解していれば、それがもたらす最大の利点も理解できるはずです。デカップリング。

そして、分離によって、コードのスケーラビリティの強化、コードの保守性の強化、単体テストの容易化など、さらなるメリットがもたらされます。

それでは、依存関係の注入を実装するにはどうすればよいでしょうか?

Java には次のメソッドがあります:

  • Setter メソッド インジェクション: 特定のプロパティのパブリック set メソッドを実装して、外部コンテナが依存オブジェクトのオブジェクトを呼び出せるようにします。タイプ 。

  • インターフェイスベースの注入: 依存型のオブジェクトを注入するための外部コンテナー用の特定のインターフェイスを実装します。

  • コンストラクターベースのインジェクション: 特定のパラメーターを使用してコンストラクターを実装し、新しいオブジェクトの作成時に依存型のオブジェクトを渡します。

  • アノテーションベースのインジェクション: コードに特定のキーワードを追加してインジェクションを実現します。

注釈は最も一般的な方法で、コメントと同様、コードとして実行されませんが、特に他の人が読むためのものです。しかし、アノテーションの読者は完全に人間であり、アノテーションの主な読者は人間に加えて、フレームワークまたはプリコンパイラーです。

Go dependency注入-wire

wireは、アノテーションベースの依存関係注入メソッドです。

wire は、Google がオープンソース化した依存関係注入ツールです。特別な go ファイル内の型間の依存関係を wire に伝えるだけで、自動的にヘルプが表示されます。コードを生成し、指定されたタイプのオブジェクトの作成を支援し、その依存関係を組み立てます。

wire には、Provider (コンストラクター) と Injector (インジェクター) という 2 つの基本概念があります。

関数

provider を提供して、これらの依存オブジェクトを生成する方法を wire に知らせます。 wire 定義した injector 関数シグネチャに従って、完全な injector 関数が生成されます。injector 関数は、必要な最後の関数です。依存関係の順序で 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 ファイルにこれを追加する必要があります。

関数では、wire.Build() を呼び出して、Mission が依存する型のコンストラクターを渡します。たとえば、NewMission() を呼び出して Mission 型を作成する必要があります。NewMission() は 2 つのパラメータ (Monster の 1 つ) を受け入れます。タイプと Player タイプのいずれか。 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
}

wire が自動的に InitMission メソッドを生成していることがわかります。このメソッドでは、プレイヤー、モンスター、ミッションが順番に初期化されます。その後、メイン関数でこの InitMission を呼び出すだけで済みます。

func main() {
  mission := InitMission("dj")

  mission.Start()
}

依存関係注入が使用される前、コードは次のようになっていました。

func main() {
  monster := NewMonster()
  player := NewPlayer("dj")
  mission := NewMission(player, monster)

  mission.Start()
}

かなり単純ではないでしょうか?ここにはオブジェクトの初期化が 3 つしかありませんが、それ以上あると、依存関係注入の利点が分からなくなる可能性があります。

例:

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 ビデオ チュートリアル プログラミング教育

以上がGo 言語の依存性注入とは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。