Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin Calling Companion Object in Abstract Class

Tags:

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.

like image 934
Julio Avatar asked Apr 06 '18 21:04

Julio


2 Answers

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
    }
}
like image 185
TpoM6oH Avatar answered Sep 23 '22 12:09

TpoM6oH


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() }
    }
}
like image 24
Alexey Romanov Avatar answered Sep 21 '22 12:09

Alexey Romanov