Suppose you are building a drawing application with various shapes (e.g., circles, squares, triangles) and want to perform different operations on these shapes without modifying their classes. This is a great scenario for using the Visitor pattern.
Define the Visitor and Element hierarchy:
// Visitor interface
public interface IShapeVisitor
{
void Visit(Circle circle);
void Visit(Square square);
void Visit(Triangle triangle);
}
// Element base class
public abstract class Shape
{
public abstract void Accept(IShapeVisitor visitor);
}
// Concrete elements
public class Circle : Shape
{
public override void Accept(IShapeVisitor visitor)
{
visitor.Visit(this);
}
}
public class Square : Shape
{
public override void Accept(IShapeVisitor visitor)
{
visitor.Visit(this);
}
}
public class Triangle : Shape
{
public override void Accept(IShapeVisitor visitor)
{
visitor.Visit(this);
}
}
Implement a concrete visitor:
public class AreaCalculator : IShapeVisitor
{
public double TotalArea { get; private set; }
public void Visit(Circle circle)
{
// Calculate and accumulate area for a circle
TotalArea += Math.PI * Math.Pow(circle.Radius, 2);
}
public void Visit(Square square)
{
// Calculate and accumulate area for a square
TotalArea += Math.Pow(square.SideLength, 2);
}
public void Visit(Triangle triangle)
{
// Calculate and accumulate area for a triangle
TotalArea += 0.5 * triangle.Base * triangle.Height;
}
}
Use the Visitor pattern to calculate the total area of different shapes without modifying their classes:
class Program
{
static void Main(string[] args)
{
var shapes = new List<Shape>
{
new Circle(5),
new Square(4),
new Triangle(3, 6)
};
var areaCalculator = new AreaCalculator();
foreach (var shape in shapes)
{
shape.Accept(areaCalculator);
}
Console.WriteLine("Total area: " + areaCalculator.TotalArea);
}
}
In this example, the Visitor pattern allows you to add new operations (e.g., calculating area) without altering the shape classes. The AreaCalculator
visitor class performs the specific operation on each shape, and the total area is calculated without modifying the shape classes, demonstrating the flexibility and separation of concerns offered by the Visitor pattern.