Factory method inside interface


#1

Let’s say there I have an interface named “Focusable”, and an object "FocusableManager"
the manager has a list of Focusables and I want that this list grows as Focusable objects are created.

The solution is then to provide a factory method, but what’s the best convention for it? do I put it in FocusableManager or in the Focusable interface like so?

interface Focusable {
    companion object {
        fun create(focusable: Focusable): Focusable {
            FocusableManager.list.add(focusable)
            return focusable
        }
    }
}

edit: Is there even better ways to do that than factory methods?


#2

The Kotlin way is to define a top-level constructor function for your interface with the same name as your interface:

fun Focusable(focusable: Focusable): Focusable {
    FocusableManager.list.add(focusable)
    return focusable
}

Although, a constructor function (or a function named create) with side effect is a very, very bad code smell.


#3

Thanks, I’m working a on small project alone so that would do it fine, but If that’s not a very good way of achieving this, then what would be one?


#4

Use an interface for Focusable factories, and implement a decorator that registers the created Focusable with the manager:

interface Focusable

interface FocusableManager {
    fun add(focusable: Focusable)
}

object DummyFocusableManager : FocusableManager {
    override fun add(focusable: Focusable) {
        println("Added: $focusable")
    }
}

interface FocusableFactory {
    fun create(): Focusable
}

class FocusableRegisteringFactory(private val delegatee: FocusableFactory,
                                  private val manager: FocusableManager) : FocusableFactory {
    override fun create(): Focusable {
        val result = delegatee.create()
        manager.add(result)
        return result
    }
}

class FirstFocusableImplementation : Focusable {
    companion object : FocusableFactory {
        override fun create() = FirstFocusableImplementation()
    }
}

class SecondFocusableImplementation : Focusable {
    companion object : FocusableFactory {
        override fun create() = SecondFocusableImplementation()
    }
}

fun main(args: Array<String>) {
    val firstFactory = FocusableRegisteringFactory(FirstFocusableImplementation.Companion, DummyFocusableManager)
    val secondFactory = FocusableRegisteringFactory(SecondFocusableImplementation.Companion, DummyFocusableManager)
    println("Created: ${firstFactory.create()}")
    println("Created: ${secondFactory.create()}")
}