Reputation: 1289
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
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
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
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