BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Design Patterns
.NET 2.0+

Visitor Design Pattern

The visitor pattern is a design pattern that separates a set of structured data from the functionality that may be performed upon it. This promotes loose coupling and enables additional operations to be added without modifying the data classes.

Example Visitor

Earlier in the article I described an example use of the visitor design pattern. In this example, the data structure holds the employees of a business, each as a single element object with properties to hold a name and monthly salary. The objects are held in a hierarchy with a single manager at the top of the tree and subordinates beneath. Each subordinate can be another manager, with their own subordinates, or a worker with none.

To create the classes for such an object structure, create a new console application project and add the code below. This defines an OrganisationalStructure class that holds the key employee. Further employees can be defined as subordinates to generate the hierarchy. To support the visitor design pattern, the employee classes include an Accept method as described previously. For managers, the accept method performs a callback to the visitor object and calls Accept for all subordinates. This ensures that a visitor will process every employee in the business.

public class OrganisationalStructure
{
    public EmployeeBase Employee { get; set; }

    public OrganisationalStructure(EmployeeBase firstEmployee)
    {
        Employee = firstEmployee;
    }

    public void Accept(VisitorBase visitor)
    {
        Employee.Accept(visitor);
    }
}


public abstract class EmployeeBase
{
    public abstract void Accept(VisitorBase visitor);

    public string Name { get; set; }

    public double MonthlySalary { get; set; }
}


public class Worker : EmployeeBase
{
    public override void Accept(VisitorBase visitor)
    {
        visitor.Visit(this);
    }
}


public class Manager : EmployeeBase
{
    public Manager()
    {
        Subordinates = new List<EmployeeBase>();
    }

    public List<EmployeeBase> Subordinates { get; private set; }

    public override void Accept(VisitorBase visitor)
    {
        visitor.Visit(this);

        foreach (EmployeeBase subordinate in Subordinates)
        {
            subordinate.Accept(visitor);
        }
    }
}

We will create two visitor classes that can be used with the object structure. The first of these will be used by the payroll software to pay the employees on a monthly basis. The code below defines the visitor base class and the payroll visitor functionality. To simulate payments, the PayrollVisitor class outputs information to the console.

public abstract class VisitorBase
{
    public abstract void Visit(Worker employee);

    public abstract void Visit(Manager employee);
}


public class PayrollVisitor : VisitorBase
{
    public override void Visit(Worker employee)
    {
        Console.WriteLine("{0} paid {1}.", employee.Name, employee.MonthlySalary);
    }

    public override void Visit(Manager employee)
    {
        Console.WriteLine("{0} paid {1} + Bonus."
            , employee.Name, employee.MonthlySalary);
    }
}

The second visitor will be used to apply a standard pay rise to all employees. The visitor includes a custom constructor that accepts a multiplier. This multiplier will be used to determine the increase in pay that each employee will receive. In the Visit method, the increase is calculated and the employee's monthly salary is changed accordingly. The increase is also added to a property that records the total increase in salary for all employees processed.

public class PayriseVisitor : VisitorBase
{
    double _multiplier;

    public double TotalIncrease { get; private set; }

    public PayriseVisitor(double multiplier)
    {
        _multiplier = multiplier;
        TotalIncrease = 0;
    }

    public override void Visit(Worker employee)
    {
        double increase = employee.MonthlySalary * _multiplier;
        employee.MonthlySalary += increase;
        TotalIncrease += increase;
        Console.WriteLine("{0} salary increased by {1}.", employee.Name, increase);
    }

    public override void Visit(Manager employee)
    {
        double increase = employee.MonthlySalary * _multiplier;
        employee.MonthlySalary += increase;
        TotalIncrease += increase;
        Console.WriteLine("{0} salary increased by {1}.", employee.Name, increase);
    }
}
21 August 2009