getit
getit

Reputation: 631

Visitor Pattern can be replaced with Callback functions?

Is there any significant benefit to using either technique? In case there are variations, the Visitor Pattern I mean is this: http://en.wikipedia.org/wiki/Visitor_pattern

And below is an example of using a delegate to achieve the same effect (at least I think it is the same)

Say there is a collection of nested elements: Schools contain Departments which contain Students

Instead of using the Visitor pattern to perform something on each collection item, why not use a simple callback (Action delegate in C#)

Say something like this

class Department
{
    List Students;
}

class School
{
    List Departments;

    VisitStudents(Action<Student> actionDelegate)
    {
        foreach(var dep in this.Departments)
        {
            foreach(var stu in dep.Students)
            {
                actionDelegate(stu);
            }
        }
    }
}

School A = new School();
...//populate collections

A.Visit((student)=> { ...Do Something with student... });

*EDIT Example with delegate accepting multiple params

Say I wanted to pass both the student and department, I could modify the Action definition like so: Action

class School
{
    List Departments;

    VisitStudents(Action<Student, Department> actionDelegate, Action<Department> d2)
    {
        foreach(var dep in this.Departments)
        {
            d2(dep); //This performs a different process.
            //Using Visitor pattern would avoid having to keep adding new delegates.
            //This looks like the main benefit so far 
            foreach(var stu in dep.Students)
            {
                actionDelegate(stu, dep);
            }
        }
    }
}

Upvotes: 5

Views: 2095

Answers (2)

Lee
Lee

Reputation: 144226

The visitor pattern is more useful when a node in a nested structure such as a tree doesn't know the concrete type of its children. The visitor is then used to dispatch behaviour based on the real type of each child object.

In your example, the school does know that it has a child Departments collection which in turn have child Student collections.

If you extended your example to include another child element of School then your code might look like:

public abstract class Manageable
{
    abstract void Accept(IManagebleVisitor visitor);
}

public interface IManageableVisitor
{
    void Visit(Department d);
    void Visit(Building b);
}

public class Department : Manageable { ... }
public class Building : Manageable { ... }

Now your School class might look like:

public class School
{
    private List<Manageable> manageables;
    public void Accept(IManageableVisitor visitor)
    {
        foreach(var m in this.manageables)
        {
            m.Accept(visitor);
        }
    }
}

The delegate approach doesn't work here since you'd need to pass a delegate for each concrete subclass of Manageable, so adding any new subclasses to the hierarchy will require a change to the School.Accpet method.

Upvotes: 4

dtb
dtb

Reputation: 217411

The visitor pattern is usually used when there are more than one type of things that are visited. You have only one type (Students), so you don't really need the visitor pattern and can just pass in a delegate instance.

Assume you'd want to visit both Departments and Students. Then you visitor would look like this:

interface ISchoolVisitor
{
    void Visit(Department department);
    void Visit(Student student);
}

Of course, you could also use delegates here as well, but it would be cumbersome to pass in multiple delegate instances -- in particular if you have more than 2 types of visited things.

Upvotes: 9

Related Questions