DIの話

この記事はICT Advent Calendar14日目の記事です。

前日はnemu_souでした。
何か作ったらしいのでえらいですね()。

nemu-sou.hatenablog.com

こんにちは、mitoです。

みなさん、DIしてますか。

DIとは

Dependency Injection のこと

DIとは、コンピュータプログラムのデザインパターンの一つで、オブジェクトなどの間に生じる依存関係をオブジェクト内のコードに直接記述せず、外部から何らかの形で与えるようにする手法。(IT用語辞典)

「依存性の注入」とよく言われています。

依存性とは

ここでいう依存性というのはあるクラス内で他のクラスを利用している状況のことです。
例えば、Aというクラス内でBクラスを利用しているということがあったとします。

class A {
    val b: B = B() // インスタンス化

    fun hoge() {
        b.greeting()
    }
}

class B {
    private val text: String = "Hello, DI"

    fun greeting() {
        print(text)
    }
}

こういう状況でAというクラスの動きにはBというクラスが必要になって、Bクラスがなかった場合にAクラスは機能しません。
これが依存で「AがBに依存している」と言われてます。

ただ、依存という言葉自体にあまり良いイメージはないと思います(薬物...?)
実は英語版のDependency injectionのページには

A "dependency" is an object that can be used

とあり、訳すと「"Dependency"は使用できるオブジェクトです」
そう、オブジェクトです。
オブジェクト指向でのオブジェクトと捉えて問題ないと思います。
そう考えると考えやすくなるかと。

注入とは

注ぎ入れること。つぎこむこと。(Google検索結果)

つまり

あるクラスに対してそのクラス内で使っている他のクラス(オブジェクト)を外部から注入・渡してあげるという感じです。

↑の例ではAクラスの中でBクラスをインスタンス化(生成)させて使っているので、外部から注入されていません。
これに対して、外部(他クラスなど)から入れて・渡してあげることです。

外部って誰?っていう気持ちになるかもしれませんが、今のところはあまり気にしなくてもいいです。(一応書いておくと、Aを使おうとしている他クラスだったりDIコンテナだったりです。)

DIの種類

DIというのは上記の説明のようにパターンの名前でしかないので、それを実現するためにはいくつか種類があります。
- Constructor Injection
- Setter Injection
- DIコンテナを使う

Constructor Injection

コンストラクタ(Constructor)で渡してあげる方法です。

class A(val b: B) { // コンストラクタで渡す
    fun hoge() {
        b.greeting()
    }
}
// Bクラスは上記のコードと同じ

Setter Injection

セッター(Setter)で渡してあげる方法です。

class A(val b: B) {
    lateinit var b: B // セッターを使って後で渡す

    fun hoge() {
        b.greeting()
    }
}
// Bクラスは上記のコードと同じ

DIコンテナを使う

DIコンテナと呼ばれるDIを実現してくれるライブラリのようなものです。
DIコンテナには多く種類がありそれぞれ使い方も全然違うのでここでは説明しないです。

なぜ使うのか

よく言われているのは - テストがしやすくなる
- 柔軟になる

ただ、これを聞いただけではへ〜そうなんだになると思います。(自分も前まで利点は知っていたけどそうなんだくらいにしか思ってなかった)

テストがしやすくなる

Bをモック化してAのテストがしやすくなります。
モックに関しての話はテストの話になってくるので省略するのですが、AクラスがBクラス内のgreeting関数をちゃんと実行できているかなどを試すことができます。

柔軟になる

今、Bクラスをインスタンス化するには、B()だけで済んでいますが、もしBクラスのインスタンス化に仕様変更が入ってめちゃくちゃ長かったり複雑だったりした場合(良い例が思いつかなかった)に、Bクラスをインスタンス化して使っているクラス(例ではAクラス)全てのインスタンス化部分を書き直さないといけなくなります。

他にもいろいろな利点や欠点があるのですが、そこは調べてください。

最後に

今年度で高専も卒業ということで、それに関する記事はまた2,3月くらいにでも書こうと思います。
卒論を書き終わった頃には技術に関する記事をまた書いていこうかなとも思っているので、卒研頑張ります。

翌日は、ねるねるです。
サーバーサイドに強いっていう印象だったけど、プロコンの時にAndroidの話をしていた気がするなって思っています。
翌日からTNG Weekみたいです。

neruneru0419.hatenablog.com