The visitor design pattern allows us to separate an algorithm from the structure that the algorithm works against. This is one of the easiest ways to adhere to the open/closed principle. because it allows us to add new algorithms without having to modify the original structure that the algorithm is run against.
The visitor design pattern core interfaces in C#:
public interface IVisitable<T>
{
void Accept(IVisitor<T> visitor);
}
public interface IVisitor<T>
{
void Visit(T item);
}
example
In the following example, I’ve defined a structure for a table. A table has many rows, and each row has a different cell for each column.
I have omitted a lot of details for brevity.
public class Table : IVisitable<Row>
{
...
public void Accept(IVisitor<Row> visitor)
{
rows.each(x => visitor.Visit(x));
}
}
public class Row : IVisitable<ICell>
{
...
public void Accept(IVisitor<ICell> visitor)
{
cells.each(x => visitor.Visit(x));
}
}
public class Column<T> : IColumn
{
...
public Column(string name)
{
this.name = name;
}
}
public class Cell<T> : ICell
{
...
public bool IsFor(IColumn otherColumn)
{
return column.Equals(otherColumn);
}
public T Value { get; private set; }
public void ChangeValueTo(T value)
{
Value = value;
}
}
We can now define different algorithms for traversing the table structure without having to modify the table structure. In this example the TotalRowsVisitor increments a counter each time it visits a row.
public class TotalRowsVisitor : IVisitor<Row>
{
public void Visit(Row item)
{
Total++;
}
public int Total { get; set; }
}
var visitor = new TotalRowsVisitor();
table.Accept(visitor);
Console.Out.WriteLine( visitor.Total );
The full source code for this entry can be downloaded from here.