Created
November 30, 2019 22:59
-
-
Save Ioane5/d60f488b543b8e0f26044c06de28705a to your computer and use it in GitHub Desktop.
How not to use Visitor Pattern
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package models | |
sealed class Expression | |
class Literal(val value: Double) : Expression() | |
class Addition(val left: Expression, val right: Expression) : Expression() | |
abstract class ExpressionOperator<T> { | |
abstract fun operate(literal: Literal): T | |
abstract fun operate(addition: Addition): T | |
fun operate(expression: Expression): T = when (expression) { | |
is Literal -> operate(expression) | |
is Addition -> operate(expression) | |
} | |
} | |
class ExpressionStringifier : ExpressionOperator<String>() { | |
override fun operate(literal: Literal) = literal.value.toString() | |
override fun operate(addition: Addition): String { | |
return "(${operate(addition.left)} + ${operate(addition.right)})" | |
} | |
} | |
class ExpressionCalculator : ExpressionOperator<Double>() { | |
override fun operate(literal: Literal) = literal.value | |
override fun operate(addition: Addition) = operate(addition.left) + operate(addition.right) | |
} | |
fun main() { | |
val expression = Addition(Literal(1.0), Literal(1000.0)) as Expression | |
// Expression to string | |
val expressionStr = ExpressionStringifier().operate(expression) | |
println("Expression: $expressionStr") | |
// Calculate Expression | |
val value = ExpressionCalculator().operate(expression) | |
println("Value: $value") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I dislike visitor pattern, because it's confusing.
I think they way object accepts something that is not part of it, just to calculate upon, is not natural.
Using dynamic way seems prettier, but it brings danger or runtime type exceptions.
So, I think this can be completely avoided by using sealed types and
when
expression, that is exhaustive, meaning that, it will remind you to handle all the types, because, it's sealed and therefore, all the inherited models are known.