Visitor Pattern

Separates the algorithm from the objects it operates on, allowing new operations to be added to the object structure without modifying the objects themselves.

Example


// Node trait representing a node in the tree
trait Node {
    fn accept(&self, visitor: &mut dyn Visitor);
}

// Leaf node in the tree
struct LeafNode {
    value: i32,
}

impl Node for LeafNode {
    fn accept(&self, visitor: &mut dyn Visitor) {
        visitor.visit_leaf_node(self);
    }
}

// Composite node in the tree
struct CompositeNode {
    children: Vec<Box<dyn Node>>,
}

impl Node for CompositeNode {
    fn accept(&self, visitor: &mut dyn Visitor) {
        visitor.visit_composite_node(self);
    }
}

// Visitor trait defining the operations to be performed on nodes
trait Visitor {
    fn visit_leaf_node(&mut self, node: &LeafNode);
    fn visit_composite_node(&mut self, node: &CompositeNode);
}

// Concrete visitor implementation
struct SumVisitor {
    sum: i32,
}

impl SumVisitor {
    fn new() -> Self {
        SumVisitor { sum: 0 }
    }
}

impl Visitor for SumVisitor {
    fn visit_leaf_node(&mut self, node: &LeafNode) {
        self.sum += node.value;
    }

    fn visit_composite_node(&mut self, node: &CompositeNode) {
        for child in &node.children {
            child.accept(self);
        }
    }
}

fn main() {
    // Create the tree structure
    let leaf1 = Box::new(LeafNode { value: 5 });
    let leaf2 = Box::new(LeafNode { value: 10 });
    let composite1 = Box::new(CompositeNode {
        children: vec![leaf1, leaf2],
    });

    let leaf3 = Box::new(LeafNode { value: 15 });
    let leaf4 = Box::new(LeafNode { value: 20 });
    let composite2 = Box::new(CompositeNode {
        children: vec![leaf3, leaf4],
    });

    let root = Box::new(CompositeNode {
        children: vec![composite1, composite2],
    });

    // Create the visitor and perform the operations on the tree
    let mut sum_visitor = SumVisitor::new();
    root.accept(&mut sum_visitor);

    println!("Sum of all leaf node values: {}", sum_visitor.sum);
}