The visitor pattern is used to separate a relatively complex set of structured data classes from the functionality that may be performed upon the data that they hold.
Setup
- Visitor:
Declare a Visite operation for each class of ConcreteElement in the object structure. The operation's name and signature identifies the class that sends the Visit request to the visitor. That lets the visitor determine the concrete class of the element being visited. Then the visitor can access the element directly through particular interface. - Concrete Visitor
Implement each operation declared by Visitor. Each operation implements a fragment of the algorithm defined for the corresponding class of object in the structure. ConcreteVisitor provides the context for the algorithm and stores the local state. This states often accumulates results during the traversal of the structure. - Element
Define an accept operation which takes a visitor as argument. - Concrete Element
Implement the operation that takes a visitor as argument. - Client
Example 1
// Step 5: Client code
fun main(args: Array<String>) {
val oneVisitor = OneVisitor()
val sightSeeing = SightSeeing()
sightSeeing.accept(oneVisitor)
}
// Step 1: Visitable Interface (Element interface)
interface Visitable{
fun accept(visitor: Visitor)
}
// Step 2: Concrete Visitable (Concrete Element)
class Palace: Visitable{
override fun accept(visitor: Visitor) {
visitor.visit(this)
}
}
class Museum: Visitable{
override fun accept(visitor: Visitor) {
visitor.visit(this)
}
}
class Monument: Visitable{
override fun accept(visitor: Visitor) {
visitor.visit(this)
}
}
class SightSeeing: Visitable{
private val visitable = arrayOf(Palace(), Museum(), Monument())
override fun accept(visitor: Visitor) {
for (v in visitable)
v.accept(visitor)
}
}
// Step 3: Visitor Interface
interface Visitor{
fun visit(visitable: Visitable)
fun visit(visitable: Palace)
fun visit(visitable: Museum)
fun visit(visitable: Monument)
}
// Step 4: Concrete Visitor
class OneVisitor: Visitor{
override fun visit(visitable: Visitable) {
println("I am visiting ${visitable.javaClass.simpleName}")
}
override fun visit(visitable: Monument) {
println("I am visiting ${visitable.javaClass.simpleName}")
}
override fun visit(visitable: Museum) {
println("I am visiting ${visitable.javaClass.simpleName}")
}
override fun visit(visitable: Palace) {
println("I am visiting ${visitable.javaClass.simpleName}")
}
}
/**
prints
I am visiting Palace
I am visiting Museum
I am visiting Monument
**/
Example 2
// Step 5: Client code
fun main(args: Array<String>) {
val customer = OneCustomer()
val shopList = arrayOf(Toothpaste(2), Tissues(6), Lotion(1))
shopList.forEach { it.accept(customer) }
println("Sum = ${customer.sum}")
}
// Step 1: Visitable Interface
interface Commodity{
fun accept(visitor: Customer)
}
// Step 2: Concrete Visitable
class Toothpaste(private val quantity: Int): Commodity{
override fun accept(visitor: Customer) {
println("Article: ${this.javaClass.simpleName}, Quantity: $quantity")
visitor.visit(visitable = this, quantity = quantity)
}
}
class Tissues(private val quantity: Int): Commodity{
override fun accept(visitor: Customer) {
println("Article: ${this.javaClass.simpleName}, Quantity: $quantity")
visitor.visit(visitable = this, quantity = quantity)
}
}
class Lotion(private val quantity: Int): Commodity{
override fun accept(visitor: Customer) {
println("Article: ${this.javaClass.simpleName}, Quantity: $quantity")
visitor.visit(visitable = this, quantity = quantity)
}
}
// Step 3: Visitor Interface
interface Customer{
fun visit(visitable: Toothpaste, quantity: Int)
fun visit(visitable: Tissues, quantity: Int)
fun visit(visitable: Lotion, quantity: Int)
}
// Step 4: Concrete Visitor
class OneCustomer: Customer{
var sum: Int = 0
override fun visit(visitable: Lotion, quantity: Int) {
sum += quantity * 30
}
override fun visit(visitable: Tissues, quantity: Int) {
sum += quantity * 10
}
override fun visit(visitable: Toothpaste, quantity: Int) {
sum += quantity * 15
}
}
/**
prints
Article: Toothpaste, Quantity: 2
Article: Tissues, Quantity: 6
Article: Lotion, Quantity: 1
Sum = 120
**/