Skip to content

Instantly share code, notes, and snippets.

@milgner
Last active December 7, 2020 09:59
Show Gist options
  • Save milgner/b9a4ae95d112a392dfa82d8934527277 to your computer and use it in GitHub Desktop.
Save milgner/b9a4ae95d112a392dfa82d8934527277 to your computer and use it in GitHub Desktop.
An idea for a simple factory in Kotlin
import kotlin.reflect.KCallable
import kotlin.reflect.KClass
import kotlin.reflect.KFunction
import kotlin.reflect.KProperty
interface IFaktory<T: Any> {
fun build() : T
}
// the P generic type doesn't work as of yet
// it is supposed to map a KProperty to a function that returns the same type as that property
fun <T: Any, P> faktory(ctor: KCallable<T>, setters: Map<KProperty<P>, () -> P>) : IFaktory<T> {
return object : IFaktory<T> {
override fun build(): T {
with(ctor) {
val settersByPropertyName = setters.mapKeys { it.key.name }
return callBy(parameters.associate { param ->
param to {
val initializer = settersByPropertyName.get(param.name)
if (initializer != null) {
initializer.invoke()
} else {
if (param.isOptional) {
null
} else {
throw NotImplementedError("Please add ${param.name} to your factory attributes")
}
}
}
})
}
}
}
}
data class Foo(val bar: String, val baz: Int) {}
val myFaktory = faktory(::Foo, mapOf(
Foo::bar to { "bar" },
Foo::baz to { 42 }
))
fun main() {
val instance = myFaktory.build()
println(instance)
}
@thedanielhanke
Copy link

thedanielhanke commented Dec 7, 2020

merge / override build params:

typealias Props<P> = Map<KProperty<P>, () -> P>

interface IFaktory<T : Any, P> {
    fun build(): T
    fun build(setters: Props<P>): T
    fun buildWith(setters: Props<P>): T
}

inline fun <reified T : Any, P> faktory(
    klass: KClass<T>,
    _setters: Props<P>
): IFaktory<T, P> {
    return object : IFaktory<T, P> {
        override fun build(): T {
            return build(_setters)
        }

        override fun buildWith(setters: Props<P>): T {
            val mergedMap = _setters
                .toMutableMap()
                .apply { setters.forEach { key, value -> 
                    merge(key, value) { _, new -> new }
                } }

            return build(mergedMap)
        }

        override fun build(setters: Props<P>): T {
.....

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment