Visitor Pattern Example
A short refresher on using the Visitor pattern.
The Visitor pattern allows functionality to be added to a class without modifying the class.
It’s useful when you have a collection of classes (Elements) that may need additional groups of functionality. A Visitor can implement functionality that applies to a group of Elements, avoiding the need to change every Element.
A simple Visitor pattern in TypeScript:
// The Element
abstract class Elem {
abstract accept<T>(visitor: Visitor<T>): T;
}
// The Visitor
interface Visitor<T> {
visitHello(element: Hello): T;
visitWorld(element: World): T;
}
// Elem implementations
class Hello extends Elem {
readonly hello = "hello";
accept<T>(visitor: Visitor<T>): T {
return visitor.visitHello(this);
}
}
class World extends Elem {
readonly world = "world";
accept<T>(visitor: Visitor<T>): T {
return visitor.visitWorld(this);
}
}
// Visitor implementation
// Create new Visitor implementations to apply different functionality to Elem classes
class HelloWorlder implements Visitor<string> {
run(element: Elem) {
return element.accept(this);
}
visitHello(element: Hello): string {
return `visitHello says: ${element.hello.toUpperCase()} world!`;
}
visitWorld(element: World): string {
return `visitWorld says: hello ${element.world.toUpperCase()}!`;
}
}
// Usage
const worlder = new HelloWorlder();
console.log(worlder.run(new World()));
console.log(worlder.run(new Hello()));
Run on the TypeScript Playground
The above script will output:
visitWorld says: hello WORLD!
visitHello says: HELLO world!
References
- Chapter 5.3 of Crafting Interpreters contains a good description
- Visitor pattern on Wikipedia