Skip to main content

JavaScript Example

/**
* The Component interface declares an `accept` method that should take the base
* visitor interface as an argument.
*/
class Component {
accept(visitor) {}
}

module.exports = Component;
/**
* The Visitor Interface declares a set of visiting methods that correspond to
* component classes. The signature of a visiting method allows the visitor to
* identify the exact class of the component that it's dealing with.
*/
class Visitor {
visitConcreteComponentA(element) {}

visitConcreteComponentB(element) {}
}

module.exports = Visitor;
const Component = require("./Component");

/**
* Each Concrete Component must implement the `accept` method in such a way that
* it calls the visitor's method corresponding to the component's class.
*/
class ConcreteComponentA extends Component {
/**
* Note that we're calling `visitConcreteComponentA`, which matches the
* current class name. This way we let the visitor know the class of the
* component it works with.
*/
accept(visitor) {
visitor.visitConcreteComponentA(this);
}

/**
* Concrete Components may have special methods that don't exist in their
* base class or interface. The Visitor is still able to use these methods
* since it's aware of the component's concrete class.
*/
exclusiveMethodOfConcreteComponentA() {
return "A";
}
}

module.exports = ConcreteComponentA;
const Component = require("./Component");

/**
* Each Concrete Component must implement the `accept` method in such a way that
* it calls the visitor's method corresponding to the component's class.
*/
class ConcreteComponentB extends Component {
/**
* Same here: visitConcreteComponentB => ConcreteComponentB
*/
accept(visitor) {
visitor.visitConcreteComponentB(this);
}

specialMethodOfConcreteComponentB() {
return "B";
}
}

module.exports = ConcreteComponentB;
const Visitor = require("./Visitor");

/**
* Concrete Visitors implement several versions of the same algorithm, which can
* work with all concrete component classes.
*
* You can experience the biggest benefit of the Visitor pattern when using it
* with a complex object structure, such as a Composite tree. In this case, it
* might be helpful to store some intermediate state of the algorithm while
* executing visitor's methods over various objects of the structure.
*/
class ConcreteVisitor1 extends Visitor {
visitConcreteComponentA(element) {
console.log(
`${element.exclusiveMethodOfConcreteComponentA()} + ConcreteVisitor1`
);
}

visitConcreteComponentB(element) {
console.log(
`${element.specialMethodOfConcreteComponentB()} + ConcreteVisitor1`
);
}
}

module.exports = ConcreteVisitor1;
const Visitor = require("./Visitor");

/**
* Concrete Visitors implement several versions of the same algorithm, which can
* work with all concrete component classes.
*
* You can experience the biggest benefit of the Visitor pattern when using it
* with a complex object structure, such as a Composite tree. In this case, it
* might be helpful to store some intermediate state of the algorithm while
* executing visitor's methods over various objects of the structure.
*/
class ConcreteVisitor2 extends Visitor {
visitConcreteComponentA(element) {
console.log(
`${element.exclusiveMethodOfConcreteComponentA()} + ConcreteVisitor2`
);
}

visitConcreteComponentB(element) {
console.log(
`${element.specialMethodOfConcreteComponentB()} + ConcreteVisitor2`
);
}
}

module.exports = ConcreteVisitor2;
/**
* Visitor Design Pattern
*
* Intent: Lets you separate algorithms from the objects on which they operate.
*/

const ConcreteComponentA = require("./ConcreteComponentA");
const ConcreteComponentB = require("./ConcreteComponentB");
const ConcreteVisitor1 = require("./ConcreteVisitor1");
const ConcreteVisitor2 = require("./ConcreteVisitor2");

/**
* The client code can run visitor operations over any set of elements without
* figuring out their concrete classes. The accept operation directs a call to
* the appropriate operation in the visitor object.
*/
function clientCode(components, visitor) {
// ...
for (const component of components) {
component.accept(visitor);
}
// ...
}

const components = [new ConcreteComponentA(), new ConcreteComponentB()];

console.log(
"The client code works with all visitors via the base Visitor interface:"
);
const visitor1 = new ConcreteVisitor1();
clientCode(components, visitor1);
console.log("");

console.log(
"It allows the same client code to work with different types of visitors:"
);
const visitor2 = new ConcreteVisitor2();
clientCode(components, visitor2);