jeudi 22 juillet 2021

Kotlin: perform the specific action on the object depending on its type

I am new to Kotlin and want to know how to solve the following problem in the most idiomatic way with this language.

Let's say we have the base class Symbol and a bunch of its subclasses: SymbolA, SymbolB, and so on. We receive a list of symbols (instances of Symbol subtypes) and want to do some action on each symbol depending on its type. Assume also that we are planning to add more subclasses of Symbol and more new kinds of actions on them in future.

Example

For example, we was asked to transform each symbol in the list with the transformation corresponding to the type of symbol (assume that the transformation is fixed for each type). I will list the possible sollutions appearing in mind.

Possible Approach 1

Maybe the simplest possible approach is to declare the following abstract method in Symbol class:

open class Symbol {
    /*...*/
    abstract fun transform() -> Symbol
}

so that each derived class should implement its corresponding transformation inside the transform() method. The problem with this approach, I think, is that we have mixed the internals of Symbols with the logic that operates on the data. What if we will be asked to add few more similar actions and so on? I think that this is exactly the case when we would like to decouple the operations from the data.

Possible Approach 2

The second approach I thought of is to use the visitor pattern. It looks nice, however, as far as I understand, it becomes problematic when we would decide to introduce additional Symbols (subclasses of Symbol).

Possible Approach 3

Use type introspection (e.g. Kotlin's is, or Java's instanceof operator). For example, we can do the following:

fun transform(symbol: Symbol) : Symbol {
    return when(symbol) {
        is SymbolA -> /*  perform the transformation of SymbolA  */
        is SymbolB -> /*  perform the transformation of SymbolB  */
            ...
        else -> TODO("Transformation is not implemented for: ${symbol::class}")
    }
}

Possible Approach 4

Use reflection. We can introduce the following interface:

interface Transformation <T: Symbol> {
    fun transform(symbol: T) -> Symbol
}

Then implement the corresponding transormation for each subclass of Symbol and use a heterogeneous map to set/get the transformation corresponding to the type of symbol. I would also expect for this solution to be the slowest one compared to the previous solutions.

Summary

What I want to know:

  1. Any other related solution (pattern) I am not aware of?
  2. Which one is the most flexible and maintainable solution to this particulat problem?
  3. Which solution is most idiomatic/natural for Kotlin language?

Thanks in advance!

Aucun commentaire:

Enregistrer un commentaire