LoginSignup
2
0

More than 3 years have passed since last update.

A Kotlinwork Locator: ことりん仕掛けのロケーター

Last updated at Posted at 2019-10-07

ジャバの異常な愛情 またはSpringはいかにしてモダンであることを止めて時代遅れになったのか」で言及されていたServiceLocatorをKotlinで作ってみました。

機能

機能 - 実装済

  • Locatorからのインスタンスの取り出し
  • Singleton/Prototypeの使い分け
  • Mockへの入れ替え

これだけやって2クラスで60行も行かないんだからもうJavaには戻れない・・

機能 - TODO

  • Enhancerによるカスタマイズを、利用側がInterceptorを書くだけで実装できるようにする
  • Locator自体のインスタンスをカスタマイズに応じて複数扱えるようにする

機能に対する要望等あれば可能な限り対応します。

解説 - TODO

テスト

サンプルテスト 実装済み

こんな感じでターゲットクラスAとモッククラスMockedAを作っておきます。

package com.lavans.kasl

open class A {
    open fun say() = "A: Hello!"
}

class MockedA : A() {
    override fun say() = "MockedA: Yo!"
}

kotlinだとoverrideするメソッドはopenにしておかなきゃいけなくて、テストのためにインターフェースを変えるのは良くなさそう。拡張メソッドでどうにかならないかな。

1) 設定一切なしでインスタンス取得

    @Test
    fun `A says Hello!`() {
        val a = Locator.get<A>(A::class)
        println(a.say())
        assertEquals("A: Hello!", a.say())
    }

ちゃんとA: Hello!が出力される。

2) AをMockedAに差し替え設定をしてから取得してみる


    @Test
    fun `MockedA says Yo!`() {
        Locator.put(A::class, MockedA::class)
        val a = Locator.get<A>(A::class)
        println(a.say())
        assertTrue(a.say().contains("Yo"))
    }

たしかに振る舞いが変わった。

3) デフォルトのsingletonでは何回getしても同じインスタンスが取れること

    @Test
    fun `Singleton returns same instance`(){
        val a = Locator.get<A>(A::class)
        val b = Locator.get<A>(A::class)
        val c = Locator.get<A>(A::class)
        val d = Locator.get<A>(A::class)
        println("$a\n$b\n$c\n$d")
        assertEquals(a, b)
        assertEquals(a, c)
        assertEquals(a, d)
    }

ちゃんと同じobject idで帰ってきますね

com.lavans.kasl.A@41675a1f
com.lavans.kasl.A@41675a1f
com.lavans.kasl.A@41675a1f
com.lavans.kasl.A@41675a1f

4) プロトタイプ指定すると別々のインスタンスになる


    @Test
    fun `Prototype returns different instance`(){
        Locator.put(A::class, type = KClassInfo.Type.Prototype)
        val a = Locator.get<A>(A::class)
        val b = Locator.get<A>(A::class)
        val c = Locator.get<A>(A::class)
        val d = Locator.get<A>(A::class)
        println("$a\n$b\n$c\n$d")
        assertNotEquals(a, b)
        assertNotEquals(a, c)
        assertNotEquals(a, d)
    }

なるほどー、全部違うIDだ。


com.lavans.kasl.A@309bde2d
com.lavans.kasl.A@42eda0a8
com.lavans.kasl.A@400f3528
com.lavans.kasl.A@522b5d4c

サンプル TODO

  • AOPでloggerを差し込んでmethodの開始と終了でlogを吐くやつやりたい。そうするとloggerとcglibへの依存が増えるな、増やしたくないな、別プロジェクトでもいいけど
2
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0