Visitor Pattern

The Visitor Pattern is a behavioral pattern in the field of software design. It defines a new way to access elements in the object structure without changing the structure itself. By doing so, the execution algorithm of the elements can change along with the visitor, with the main intention being to separate the data structure from the data operation, thus resolving the coupling issue between a stable data structure and volatile operations.

Description

In object-oriented programming and software engineering, the visitor design pattern is a method that separates algorithms from the object structure on which they operate. The practical result of this separation is the ability to add new operations to an existing object structure without modifying it, in compliance with the Open/Closed Principle.

Advantages

  • Adheres to the Single Responsibility Principle. In scenarios suitable for the visitor pattern, the operations that need to be encapsulated in the visitor within the element class are generally unrelated to the class itself and are volatile. Using the visitor pattern not only aligns with the Single Responsibility Principle but also enables extension of the volatile operations without modifying the element class itself.
  • Good extensibility. The element class can be extended by accepting different visitors to implement different operations.

Disadvantages

  • Concrete elements expose details to visitors, violating the Law of Demeter.
  • Modifying concrete elements can be challenging.
  • Violates the Dependency Inversion Principle by depending on concrete classes instead of abstractions.

Applicable Scenarios

  • When there are operations unrelated (or weakly related) to an object, and to avoid polluting the object with these operations, the visitor pattern can be used to encapsulate these operations in visitors.
  • When a group of objects has similar operations, to avoid extensive code repetition, these repetitive operations can also be encapsulated in visitors.

Implementation

// Taking the example of a zoo simulation, let's suppose we have different kinds of animals, each capable of making different sounds.

class Monkey {
    shout() {
        console.log("Ooh oo aa aa!");
    }

    accept(operation) {
        operation.visitMonkey(this);
    }
}

class Lion {
    roar() {
        console.log("Roaaar!");
    }

    accept(operation) {
        operation.visitLion(this);
    }
}

class Dolphin {
    speak() {
        console.log("Tuut tuttu tuutt!");
    }

    accept(operation) {
        operation.visitDolphin(this);
    }
}

const speak = {
    visitMonkey(monkey) {
        monkey.shout();
    },
    visitLion(lion) {
        lion.roar();
    },
    visitDolphin(dolphin) {
        dolphin.speak();
    }
}

// ...

// We can achieve this by simply giving animals an inheritance hierarchy
// But whenever a new action must be added to animals, we would have to modify animals
// And now we don't need to.
// For example, if we were asked to add the jumping behavior to animals, we could easily do so by creating a new visitor.

const jump = {
    visitMonkey(monkey) {
        console.log("Jumped 20 feet high! on to the tree!");
    },
    visitLion(lion) {
        console.log("Jumped 7 feet! Back on the ground!");
    },
    visitDolphin(dolphin) {
        console.log("Walked on water a little and disappeared");
    }
}

// ...

```javascript
lion.accept(speak);     // Roaaar!
lion.accept(jump);      // Jumped 7 feet! Back on the ground! 

dolphin.accept(speak);  // Tuut tutt tuutt! 
dolphin.accept(jump);   // Walked on water a little and disappeared
})();

## EveryDay

https://github.com/WindrunnerMax/EveryDay

## Reference

https://www.runoob.com/design-pattern/visitor-pattern.html https://github.com/sohamkamani/javascript-design-patterns-for-humans#-visitor https://www.bookstack.cn/read/design-pattern-in-javascript/design-pattern-visitor-pattern-README.md