算譜王におれはなる!!!!

偏りはあると思うけど情報技術全般についてマイペースに書くよ。

Kotlin用DIフレームワークをつくってみた

つくってみました。

その名もInjeKTor

この名前かなり気に入ってます。

全コードはこちら→https://github.com/ntaro/InjeKTor

以前書いたエントリでKotlinの委譲のための機能を紹介しました。

これを活かすためにコンストラクタ・インジェクションを行います。

例えばこんな感じのインタフェースと実装クラスがあったとします。

trait Foo
class FooImpl: Foo

trait Bar
class BarImpl(foo: Foo): Bar, Foo by foo

class Baz(bar: Bar): Bar by bar

Bazを使いたかったら通常はこうします。

val baz = Baz(BarImpl(FooImpl()))

InjeKTorを使うと次のように書けます。

val injector = createInjector {
    javaClass<Foo>() to javaClass<FooImpl>()
    javaClass<Bar>() to javaClass<BarImpl>()
}

val baz = injector.getInstance(javaClass<Baz>())

createInjector関数でInjectorインスタンスを生成しています。引数に関数オブジェクトを取って、そこでインタフェースと実装クラスの対応関係を設定しています。Injector#getInstanceで依存性を注入されたBazクラスのインスタンスを生成して返しています。

プロパティへのインジェクションもできます。

class Hoge

class Fuga {
    private val hoge by LazyInjector(javaClass<Hoge>())
}

KotlinのDelegated Propertyという機能を使って実現しています。

KotlinでGuiceを使う

KotlinからGuice、使えます→Kotlin + Guiceやってみた

Guice使って最初の例と同じのを書くとこうなります。

trait Foo
class FooImpl : Foo

trait Bar
class BarImpl [Inject](foo: Foo) : Bar, Foo by foo

class Baz [Inject](bar: Bar) : Bar by bar

fun main(args: Array<String>) {
    val injector = Guice.createInjector(object: AbstractModule() {
        override fun configure() {
            bind(javaClass<Foo>()).to(javaClass<FooImpl>())
            bind(javaClass<Bar>()).to(javaClass<BarImpl>())
        }
    })

    val baz = injector.getInstance(javaClass<Baz>())
}

だいたいInjeKTorと同じですね。。

InjeKTor、自分でごりごり処理書かないでGuiceラッパに路線変更しようかな...