出来そうだなと思ったのでお試し。
Minimal Cake PatternといえばScalaにおけるDIの実装パターンの1つで、コンパイル時に依存性を解決でき、DIコンテナ使ってるときにやりがちなDI用アノテーションのつけ忘れて実行時エラーが起きるみたいなことが無いのが特徴。
かつコンパイルが通ればDIできているという安心感のプログラミング体験も最高。
あとは言語機能だけでDIできるので、AWS Lambdaみたいなフットプリントを小さくしたい環境とかで役立つかもしれない。
Kotlinでもだいたい似たようなことができるぞ
import java.time.Clock import java.time.Instant import java.time.ZoneId interface UseClock { val clock: Clock } interface ISystemClock: UseClock { override val clock: Clock get() = Clock.systemUTC() } interface IFixedClock: UseClock { override val clock: Clock get() = Clock.fixed(Instant.parse("2023-01-20T12:34:56.999999Z"), ZoneId.of("UTC")) } abstract class StopWatch(): UseClock { private var started: Instant? = null fun start() { started = clock.instant() } fun stop() { started?.let { started -> val elapsed = clock.instant().toEpochMilli() - started.toEpochMilli() println("elapsed: $elapsed") } ?: throw IllegalStateException("not started") } } fun main() { val systemClockStopWatch = object : StopWatch(), ISystemClock {} systemClockStopWatch.start() Thread.sleep(1000) systemClockStopWatch.stop() val fixedClockStopWatch = object : StopWatch(), IFixedClock {} fixedClockStopWatch.start() Thread.sleep(1000) fixedClockStopWatch.stop() }
元のScala版のMinimal Cake Patternだと MixinSystemClock
となっているがKotlinにmixinの機構はないのでので ISystemClock
としている。
また、Scala版では MixinSystemClock
は UseClock
を継承する必要はないが、このKotlinの実装においては ISystemClock
は UseClock
を継承しないと object: Stopwatch(): ISystemClock {}
のコンパイルが通らない点に留意する。
参考