I have a class, Base
that is an abstract class and is defined as:
abstract class Base() {}
I'd like to create a handful of derived classes from this base class:
class A : Base() {}
class B : Base() {}
class C : Base() {}
I would like to be able to call a common function create
that does some initialization work and returns the specified derived class (e.g. A
). For example, something like the following would be ideal:
val a = A.create() // `a` now holds an instance of `A`.
val b = B.create()
val c = C.create()
Initially I tried to use a companion object in the abstract class as a sort of static funcion:
abstract class Base {
companion object {
fun create() : Base {
// Do some initialization and return the derived class
// of the object. Obviously I can't return `Base` as I've
// indicated above since it is an abstract class. This is
// what I'm confused about: How do I return a copy of the
// _derived_ class here? Is this impossible? I think it
// might be...
return Base() // <-- This doesn't work. What should be returned?
}
}
}
Then in the derived class:
class A : Base() {
companion object {
fun create() : A = Base.create()
}
}
This doesn't work, for obvious reasons. Namely, I can't return an instance of the abstract class Base
. Is there an easy way to accomplish the var a = A.create()
paradigm? The code for create
will be identical across derived classes, so I wanted to avoid having to recreate the functionality in each class I create.
If the initialization logic is the same and is based on the functionality specified in the Base
class you can also do it like this:
abstract class Base() {
protected fun init(): Base {
// do the initialization
return this
}
}
class A : Base() {
companion object {
fun create() = A().init() as A
}
}
abstract class Base {
companion object {
inline fun <reified T : Base> create() : T {
// you can use T::class here
}
}
}
class A : Base() {
companion object {
fun create() : A = Base.create() // inferred to Base.create<A>()
}
}
may work but probably need to use unsafe reflection. It depends on what exactly you want to do in create
... A better practice would be to pass whatever is different between the classes as a function, e.g.
abstract class Base {
companion object {
inline fun <reified T : Base> create(f: () -> T) : T {
val instance = f()
// do something
return instance // or something created from it
}
}
}
class A : Base() {
companion object {
fun create() : A = Base.create { A() }
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With