はじめに
現在インターンで業務をしているジュニアエンジニアが勉強中の技術をアウトプットしています。
間違っていることもあると思われるので、その際は指摘いただけると幸いです。
DIとは
まず初めにそもそもDIとは何者なのかを解説します。
DIとは「Dependency Injection」の略で、直訳すると「依存性注入」と言われたりしています。
具体的には依存元のクラスのコンストラクタやメソッド内で依存先のクラスを初期化するのではなく、依存元のクラスの初期化時にコンストラクタの引数に対して、依存先のクラスのインスタンスを渡してあげようということです。
そうすることによってクラス同士が疎結合になるので、保守性が大幅にアップするというメリットがあります。
文章だとわかりにくいので実際のコードで考えてみます。
以下のコードはDIしていない例です。
Hoge構造体のHogeMethodの中でFuga構造体を初期化しているので、密結合となっています。
type Hoge struct {
}
func (h *Hoge) HogeMethod() string {
f := Fuga{}
return f.fugaMethod
}
type Fuga struct {
}
func (fuga *Fuga) FugaMethod() string {
return "fuga"
}
func main() {
h := Hoge{}
fmt.Pirngln(h.HogeMethod())
}
以下のコードはDIしている例です。
クラスの依存関係が疎結合になっています。
NewHogeとNewFugaの二つの関数はオブジェクト(構造体)を生成するファクトリーメソッドです。
// interface
type HogeInterface interface {
HogeMethod() string
}
type FugaInterface interface {
FugaMethod() string
}
// 構造体とメソッド
type Hoge struct {
f FugaInterface
}
func (h *Hoge) HogeMethod() string {
return h.f.FugaMethod()
}
type Fuga struct{}
func (f *Fuga) FugaMethod() string {
return "fuga"
}
// ファクトリーメソッド
func NewHoge(f FugaInterface) HogeInterface {
return Hoge{f}
}
func NewFuga() FugaInterface {
return Fuga{}
}
func main() {
// 依存関係の注入
fuga := NewFuga()
hoge := NewHoge(fuga)
// HogeMethod()の実行
fmt.Println(hoge.HogeMethod())
}
ここまででDIの例を見てきました。 上記のコードは小規模ですが、実際の現場だとドメイン駆動設計やClean Architectureなどの設計パターンを採用し、クラス関係が複雑になってきます。 一つのクラスが複数のクラスをプロパティに保持して、さらにその注入されたクラスが複数のクラスをプロパティとして保持するなど、マトリョーシカのように連なっていきます。 そのようなコードの依存関係の注入はコードとして書くのが面倒です。 それを解決してくれるのが、google/wireというライブラリです。
実際にwireを使ってみる
先ほどのコードをwireを使って書き換えてみます。
まずはライブラリをインストールします。
go install github.com/google/wire/cmd/wire@latest
続いてwire.goファイルを作成し、以下のようにwire.Build内にファクトリーメソッドを記述します。
//go:build wireinject
// +build wireinject
package injection
import (
"github.com/wire-test/hoge"
"github.com/wire-test/fuga"
"github.com/google/wire"
)
func InitializeHoge() hoge.HogeInterface {
wire.Build(
// fuga
fuga.NewFuga,
// hoge
hoge.NewHoge,
)
return &hoge.Hoge{}
}
wireコマンドを実行します。
wire
wire_gen.goが自動生成されます。
内容は以下の通りです。
依存関係の注入部分をInitializeHoge関数内に自動生成してくれたのが分かると思います。
後はInitializeHoge関数を呼び出せば、hoge構造体が戻り値として返されます。
// Code generated by Wire. DO NOT EDIT.
//go:generate go run github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject
package injection
import (
"github.com/wire-test/hoge"
"github.com/wire-test/fuga"
)
// Injectors from wire.go:
func InitializeHoge() hoge.HogeInterface {
fuga := fuga.NewFuga()
hoge := hoge.NewHoge(fuga)
return hoge
}