Borja
Borja

Reputation: 1289

Create abstract class with generic Type in Kotlin

I am so confused, I've been searching how kotlin generics work, but I don't get it at all.

Basically, I have BaseAnimalDetail class, which is being used with some classes extending Animal class. At the moment, there are a lot of when in the BaseAnimalDetail class, so my goal is to avoid all those when, just extending BaseAnimalDetail whenever I need, for each class that extends Animal`

open class BaseAnimalDetail<T : Animal?> : LinearLayout{
    private var animal: T? = null
    
    fun setAnimal(animal:T){
        this.animal = animal
    }

    private fun play() {
        when(animal){
           is Horse -> playWithHorse...
           is Dog -> playWithDog...
           is Cat -> playWithCat...
        }
        animal?.let { it.play() } //this is not working but animal?.play works fine, WHY?
    }
    ...More code
}

As you can see, when is super ugly, so I would like to make BaseAnimalDetail abstract and implement it like I said.

Code above is just an example, but it would help me to understand how generics work in Kotlin. It's mandatory for me to have the T var in the base class

Furthermore, WHY animal?.let { it.play() } does not compile?

Upvotes: 0

Views: 1502

Answers (3)

Tenfour04
Tenfour04

Reputation: 93872

In the case you're describing, you want each type of Animal to have its own BaseAnimalDetail subclass to go with it. So you should make BaseAnimalDetail an abstract class, and then you can create subclasses for each Animal.

By the way, since Kotlin has properties, it is redundant to make animal private and have a setter function.

abstract class BaseAnimalDetail<T : Animal> {
    var animal: T? = null
    abstract fun play()
}

class CatDetail: BaseAnimalDetail<Cat>(){
    override fun play() {
        println("toss yarn to $animal")
    }
}

But if all these different functions are different for each type of Animal, it sounds to me like you shouldn't have a separate BaseAnimalDetail class at all, and its functionality should just be in the various Animal classes. Alternatively, if there are certain behaviors that some animals share, you can create various behavior classes that can be added to the Animal class (composition design strategty).

Upvotes: 2

iamanbansal
iamanbansal

Reputation: 2752

Not sure why do you need generics for this, here is my implementation

abstract class Animal {
    abstract fun play()
}

class Horse : Animal() {
    override fun play() {
        playWithHorse()
    }
    private fun playWithHorse() {}
}

class Dog : Animal() {
    override fun play() {
        playWithDog()
    }
    private fun playWithDog() {}
}


open class BaseAnimalDetail(var animal: Animal?=null) {
    private fun play() {
       animal?.play()
    }
}

class HorseDetail(var horse: Horse? = null): BaseAnimalDetail(horse){

}

You can remove play func from BaseAnimalDetail, instead directly call horse?.play() too.

Upvotes: 0

P.Juni
P.Juni

Reputation: 2485

Not sure if understand u correctly, but what u could do is as u said - transform your BaseAnimalDetail to abstract class with abstract fun fun play() and let Animal class to extend BaseAnimalDetail or let ur Horse, Dog extend it directly.

abstract class BaseAnimalDetail {
    abstract fun play()
}

open class Animal : BaseAnimalDetail() {
    override fun play() = Unit
}

class Horse : Animal() {

    override fun play() {
        playWithHorse()
    }

    private fun playWithHorse() {}
}

class Dog : BaseAnimalDetail() {

    override fun play() {
        playWithDog()
    }

    private fun playWithDog() {}
}

Also "whenever I need" could be provided by an interface since our goal is to provide a function and there is no deeper logic there.

Upvotes: 0

Related Questions