Home > Software design >  Generic Kotlin factory to DRY constructor parameters
Generic Kotlin factory to DRY constructor parameters

Time:11-01

I have the following simple class hierarchy.

abstract class B {
  abstract val o : Int
}

class D1 (m: Int, n: Int) : B() {
  override val o = m   n
}

class D2 (m: Int, n: Int) : B() {
  override val o = m * n
}

I need a "factory function" f that gives me instances of D1 or D2 by calling it as f<D1>() or f<D2>() with hard coded parameters, say 3 and 4. The following doesn't work but illustrates what I need:

// won't compile; just demonstrates what I need
fun < T : B > f () : T {
  return T(3, 4)  // i. e. return T.constructor(m, n)
}

How to best accomplish this? Any DRY way is fine as long I don't have to repeat 3, 4 all over my code when I instantiate D1 or D2

CodePudding user response:

The only way to do it is via reflection and reified type parameter:

inline fun <reified T : B> f(m: Int = 3, n: Int = 4): T {
    val constructor = T::class.constructors.first {
        it.parameters.size == 2 &&
                it.parameters.all { param -> param.type == Int::class }
    }
    return constructor.call(m, n)
}

CodePudding user response:

Here's an alternate way without reflection, but you have to manually type out a line for each class you want to handle.

inline fun <reified T : B> f(): T{
    val m = 3
    val n = 4
    return when (T::class) {
        D1::class -> D1(m, n)
        D2::class -> D2(m, n)
        else -> error("Unsupported type ${T::class}")
    } as T
} 
  • Related