Visitor
- Allows to add new operation to an object structure without modifying it
- Use this approach when object structure is stable, and you want to support new operation
Classical Structure
Scenario
Problem
- Violates Open Closed Principle
- Logic for each operation is spread across different classes
internal interface IHtmlNode
{
void Highlight();
}
internal class HeadingNode: IHtmlNode
{
public void Highlight()
{
Console.WriteLine("Highlight heading");
}
}
internal class AnchorNode : IHtmlNode
{
public void Highlight()
{
Console.WriteLine("Highlight anchor");
}
}
internal class HtmlDocument
{
List<IHtmlNode> nodes = new List<IHtmlNode>();
public void Add(IHtmlNode node)
{
nodes.Add(node);
}
public void Highlight()
{
foreach (IHtmlNode node in nodes)
{
node.Highlight();
}
}
}
Solution
internal interface IOperation
{
void Apply(HeadingNode node);
void Apply(AnchorNode node);
}
internal interface IHtmlNode
{
void Apply(IOperation operation);
}
internal class HeadingNode: IHtmlNode
{
public void Apply(IOperation operation)
{
operation.Apply(this);
}
}
internal class AnchorNode : IHtmlNode
{
public void Apply(IOperation operation)
{
operation.Apply(this);
}
}
internal class HeadingNode: IHtmlNode
{
public void Apply(IOperation operation)
{
operation.Apply(this);
}
}
internal class HtmlDocument
{
List<IHtmlNode> nodes = new List<IHtmlNode>();
public void Add(IHtmlNode node)
{
nodes.Add(node);
}
public void Apply(IOperation operation)
{
foreach (IHtmlNode node in nodes)
{
node.Apply(operation);
}
}
}
internal class HighlightOperation : IOperation
{
public void Apply(HeadingNode node)
{
Console.WriteLine("Highlight heading");
}
public void Apply(AnchorNode node)
{
Console.WriteLine("Highlight anchor");
}
}
internal class PlainText: IOperation
{
public void Apply(HeadingNode node)
{
Console.WriteLine("PlaintText heading");
}
public void Apply(AnchorNode node)
{
Console.WriteLine("PlaintText anchor");
}
}
internal class HtmlDocument
{
List<IHtmlNode> nodes = new List<IHtmlNode>();
public void Add(IHtmlNode node)
{
nodes.Add(node);
}
public void Apply(IOperation operation)
{
foreach (IHtmlNode node in nodes)
{
node.Apply(operation);
}
}
}
public class Program
{
static void Main(string[] args)
{
var document = new HtmlDocument();
document.Add(new HeadingNode());
document.Add(new AnchorNode());
document.Apply(new HighlightOperation());
document.Apply(new PlainText());
}
}
Example Structure
Example Code