Ever visited a museum where a friendly tour guide takes you through the exhibits, offering fascinating insights without changing a thing about the art on display? That’s the Visitor Pattern in action! It lets you add new operations to a collection of objects without altering their classes—just like a tour guide who can comment on any exhibit without having to modify the artwork.
Why Bother with It?
- Separation of Concerns: Just as the tour guide handles all the commentary while the exhibits remain unchanged, the Visitor Pattern separates the operations (or “what to do”) from the object structure (the exhibits).
- Extensibility: Want to add new insights or analysis to the exhibits? You simply create a new visitor (new tour guide) without modifying the existing exhibits.
- Clear and Organized: By keeping the operations separate, your code stays tidy. The exhibits don’t get cluttered with extra methods—they simply “accept” a visitor to perform actions on them.
How It Works (In Plain English)
- The Exhibits (Elements): These are your objects—in our analogy, the artworks in the museum.
- The Tour Guide (Visitor): The visitor is like the tour guide who walks through the museum, examining each exhibit and offering unique commentary.
- Accepting a Visitor: Each exhibit provides an “Accept” method that lets the tour guide come in and perform its magic. The guide then “visits” each exhibit, executing operations that vary by exhibit type.
C# Code Example
using System;
using System.Collections.Generic;
// Visitor Interface: Defines visit methods for each type of exhibit.
public interface IExhibitVisitor
{
void VisitPainting(Painting painting);
void VisitSculpture(Sculpture sculpture);
}
// Concrete Visitor: Our friendly tour guide.
public class TourGuide : IExhibitVisitor
{
public void VisitPainting(Painting painting)
{
Console.WriteLine($"TourGuide: This painting, '{painting.Title}', is a masterpiece of {painting.ArtStyle} art!");
}
public void VisitSculpture(Sculpture sculpture)
{
Console.WriteLine($"TourGuide: Behold, the sculpture '{sculpture.Title}'—a stunning example of {sculpture.Material} craftsmanship!");
}
}
// Element Interface: Each exhibit can accept a visitor.
public interface IExhibit
{
void Accept(IExhibitVisitor visitor);
}
// Concrete Element: A painting exhibit.
public class Painting : IExhibit
{
public string Title { get; private set; }
public string ArtStyle { get; private set; }
public Painting(string title, string artStyle)
{
Title = title;
ArtStyle = artStyle;
}
public void Accept(IExhibitVisitor visitor)
{
visitor.VisitPainting(this);
}
}
// Concrete Element: A sculpture exhibit.
public class Sculpture : IExhibit
{
public string Title { get; private set; }
public string Material { get; private set; }
public Sculpture(string title, string material)
{
Title = title;
Material = material;
}
public void Accept(IExhibitVisitor visitor)
{
visitor.VisitSculpture(this);
}
}
// Client Code: The museum where exhibits are showcased.
public class Program
{
public static void Main()
{
List<IExhibit> exhibits = new List<IExhibit>
{
new Painting("Starry Night", "Post-Impressionism"),
new Sculpture("The Thinker", "Bronze")
};
IExhibitVisitor tourGuide = new TourGuide();
// The tour guide visits each exhibit.
foreach (var exhibit in exhibits)
{
exhibit.Accept(tourGuide);
}
}
}
The Takeaway
The Visitor Pattern is like having an expert museum tour guide who can add new insights to every exhibit without changing the artwork itself. By encapsulating operations in a visitor, you can add functionality to a whole object structure in a neat, decoupled way. Next time you need to perform multiple operations on a complex set of objects, consider inviting a visitor to your code’s “museum”!
Happy coding—and enjoy the art of design patterns!