FooModule
、BarModule
、BazModule
を組み合わせてオブジェクトグラフを生成trait FooModule {
// This module provides:
lazy val foo = "foo"
lazy val fooBar = s"($foo+$bar)"
lazy val fooBarBaz = s"($fooBar+$barBaz+$bazFoo)"
// This module depends on:
def bar: String
def barBaz: String
def bazFoo: String
}
object FooBarBazComponent
extends FooModule with BarModule with BazModule {
val baz = "baz"
}
interface FooModule {
// This module provides:
val foo get() = "foo" // Kotlin 1.1
val fooBar get() = "(foo+$bar)"
val fooBarBaz get() = "($fooBar+$barBaz+$bazFoo)"
// This module depends on:
val bar: String
val barBaz: String
val bazFoo: String
}
object FooBarBazComponent : FooModule, BarModule, BazModule {
override val baz = "baz"
}
Object 'FooBarBazComponent' must override public open val foo: String defined in FooModule because it inherits multiple interface methods of it
class ObjectGraph() :
FooModule by FooModuleImpl(),
BarModule by BarModuleImpl(),
BazModule by BazModuleImpl()
// これではだめ。
// なぜなら FooModuleImpl が BarModule によって提供される機能に
// 依存したくでもできない (参照できない) ため。
XxxModule
インターフェイスにモジュールの依存も宣言されているinterface FooModule {
// This module provides:
val foo: String
// ... (略) ...
// This module depends on:
interface Dependencies {
val bar: String
// ... (略) ...
}
class Impl(private val d: Lazy<Dependencies>) : FooModule {
override val foo get() = "foo"
// ... (略) ...
}
}
interface FooBarBazComponent {
interface Dependencies {
val baz: String
}
class ObjectGraph(self: Lazy<ObjectGraph>, d: Dependencies) :
Dependencies by d,
FooModule by FooModule.Impl(self), FooModule.Dependencies,
BarModule by BarModule.Impl(self), BarModule.Dependencies,
BazModule by BazModule.Impl(self), BazModule.Dependencies
companion object {
fun create(d: Dependencies): ObjectGraph =
AtomicReference<ObjectGraph>().let { r ->
ObjectGraph(lazy { r.get() }, d).apply { r.set(this) } }
}
}
Lazy
によりデリゲーション先オブジェクトに自分自身を渡す (無理やり感)XxxProvider
というインターフェイスを経由して依存関係を記述interface FooProvider {
val foo: String
}
// ... こんな感じで ...
interface FooModule :
// 提供するオブジェクト一覧
FooProvider, FooBarProvider, FooBarBazProvider {
interface Dependencies :
// 依存するオブジェクト一覧
BarProvider, BazBarProvider
class Impl(private val d: Lazy<Dependencies>) : FooModule {
// ... 実装 ...
}
}
class Hoge(d: Dependencies) {
interface Dependencies :
FooProvider
fun useFoo() {
// d.foo を使う
d.foo + "bar"
}
}
// そうするとモジュール側の実装は単純になる
module HogeModule : HogeProvider {
/* 略 */
class Impl(private val d: Lazy<Dependencies>) : HogeModule {
override val hoge by lazy { Hoge(d.value) }
}
}
Lazy
でデリゲーション先に自分を渡すとか、依存オブジェクトをインターフェイスにまとめるとかは使えそうDependencies
の定義などに使えそう