Visitor Pattern

The visitor pattern is a behavioral design pattern that allows you to add further operations to objects without having to modify them. It involves creating a visitor class that implements a visitor interface and then passing it to elements of the object structure.

// Define the Visitor trait
trait Visitor {
    fn multiply_by_two(&mut self, element: &mut ElementA);
    fn add_ten(&mut self, element: &mut ElementB);
}

// Define the Element trait
trait Element {
    fn accept(&mut self, visitor: &mut dyn Visitor);
}

// Define concrete elements
struct ElementA {
    data: i32,
}

struct ElementB {
    data: i32,
}

impl Element for ElementA {
    fn accept(&mut self, visitor: &mut dyn Visitor) {
        visitor.multiply_by_two(self);
        println!("After the visit: {:?}", self.data);
    }
}

impl Element for ElementB {
    fn accept(&mut self, visitor: &mut dyn Visitor) {
        visitor.add_ten(self);
        println!("After the visit: {:?}", self.data);
    }
}

// Define a concrete visitor
struct ConcreteVisitor;

impl Visitor for ConcreteVisitor {
    fn multiply_by_two(&mut self, element: &mut ElementA) {
        println!("Visiting ElementA: {:?}", element.data);
        element.data *= 2;
    }

    fn add_ten(&mut self, element: &mut ElementB) {
        println!("Visiting ElementB: {:?}", element.data);
        element.data += 10;
    }
}

fn main() {
    let elements: Vec<Box<dyn Element>> = vec![Box::new(ElementA { data: 10 }), Box::new(ElementB { data: 5 })];
    let mut visitor = ConcreteVisitor;

    for mut element in elements {
        element.accept(&mut visitor);
    }
}
  • The Visitor trait defines methods for visiting different types of elements.
  • The Element trait defines an accept method that takes a mutable reference to a Visitor.
  • ElementA and ElementB are concrete implementations of the Element trait.
  • ConcreteVisitor is a concrete implementation of the Visitor trait.
  • In the main function, we create a list of elements and a visitor, and then we iterate over the elements, passing the visitor to each element's accept method.

This pattern allows you to add new operations to existing object structures without modifying those structures.