An example of a visitor pattern in Kotlin.
Table of contents for design patterns in Kotlin
In object-oriented programming and software engineering, the visitor design pattern is a way of separating an algorithm from an object structure on which it operates. A practical result of this separation is the ability to add new operations to existing object structures without modifying the structures. It is one way to follow the open/closed principle. Wikipedia
Example:
ShapeVisitable
interface ShapeVisitable {
fun <R> accept(visitor: ShapeVisitor<R>): R
}
ShapeVisitor
interface ShapeVisitor<out R> {
fun visit(shape: Circle): R
fun visit(shape: Square): R
}
Circle
class Circle(val diameter: Long) : ShapeVisitable {
override fun <R> accept(visitor: ShapeVisitor<R>): R = visitor.visit(this)
}
Square
class Square(val size: Long) : ShapeVisitable {
override fun <R> accept(visitor: ShapeVisitor<R>): R = visitor.visit(this)
}
PrintVisitor
class PrintVisitor : ShapeVisitor<String> {
override fun visit(shape: Circle): String = "Circle: diameter=${shape.diameter}"
override fun visit(shape: Square): String = "Square: size=${shape.size}"
}
FileSaveVisitor
class FileSaveVisitor : ShapeVisitor<String> {
override fun visit(shape: Circle): String = "C:d=${shape.diameter}"
override fun visit(shape: Square): String = "S:s=${shape.size}"
}
Usage:
fun main() {
val shapes = mutableListOf<ShapeVisitable>().apply {
add(Circle(10))
add(Square(12))
}
val printVisitor = PrintVisitor()
val fileSaveVisitor = FileSaveVisitor()
shapes.map { shape -> shape.accept(printVisitor) }.forEach {
println(it)
}
File("visitor_shapes.txt").writer().use { writer ->
writer.write("")
shapes.map { shape -> shape.accept(fileSaveVisitor) }.forEach { shapeData ->
writer.appendln(shapeData)
}
writer.flush()
}
}
Result
Circle: diameter=10
Square: size=12
visitor_shapes.txt
C:d=10
S:s=12