MA

  • Home
  • About

Visitor Pattern Example

August 2022

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

  • Next: Git Grabbag
  • Previous: Patch SF Mono with Nerd Font Icons
RSS Feed Edit this page on Github