Sunday, June 30, 2013

Acyclic Visitor implementation without casting to concrete visitor types

Abstract

Visitor is a powerful design pattern which gives strong advantages in design of an applications. In particular, visitor makes it possible to implement an visiting actions (an algorithms) over objects structures without changing it. Moreover, it is very convenient way to separate different action implementations in different visitor classes. It guides to think about single responsibility and open/closed principles.

public class MyVisitor
{
   public void Visit(SomeObjectA a)
   {
       // Algorithm comes here
   }

   public void Visit(SomeObjectB b)
   {
       // Algorithm comes here
   }
}

Acyclic visitor goes even farther and separates visitors for every object in the structure implementation into two separated (decoupled) classes. It gives a great power of extending an object structure without affecting any existing visitor. And you know how painful it can be to extend an existing application – in majority of cases it will be necessary to change existing code which responsibility  and implementation is already closed, developed and tested.

public class MySomeObjectAVisitor : IVisitor<SomeObjectA>
{
   public void Visit(SomeObjectA a)
   {
       // Algorithm comes here
   }
}

public class MySomeObjectBVisitor : IVisitor<SomeObjectB>
{
   public void Visit(SomeObjectB b)
   {
       // Algorithm comes here
   }
}

The Problem

If you look for acyclic visitor implementation examples it always comes into casting to concrete visitor type:

class SomeObjectA : BaseObject
{
  public override void Accept(IVisitor visitor)
  {
     // Coupling
     if (visitor is IVisitor<MySomeObject>) 
     {
       // Casting
       ((IVisitor<MySomeObject>)visitor).Visit(this);
     }
   }
}

In this post I will try to give an implementation which overcomes above limitations by extending acyclic visitor with repository and unit of work patterns.

Prerequisites

In the following solution I chose to use unity for IoC container and FakeItEasy for dynamic mocking.

Solution

So lets start with definition of the object structure. I will use Shape class as an abstract class with Box, Circle and Canvas derived classes, while Canvas is a composition of any shapes. Composition pattern is an important part of the structure because implementation of it visitor is most trickiest part.

public abstract class Shape
{
}

public class Box : Shape
{
    public double Side { get; set; }
}


public class Canvas : Shape, IEnumerable<Shape>
{
    private readonly List<Shape> _shapes = new List<Shape>();

    public double Height { get; set; }

    public double Width { get; set; }

    public void Add(Shape s)
    {
        _shapes.Add(s);
    }

    public IEnumerator<Shape> GetEnumerator()
    {
        return _shapes.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

OK, now we have an objects structure, thus let’s define visitor interface:

public interface IVisitor<in T>
{
    void Visit(T to);
}

Now when it comes to a visitor pattern we have to implement some functionality for each object type in the hierarchy. So lets implement the visitors which can draw the objects using some IGraphics interface.

class BoxDrawVisitor : IVisitor<Box>
{
    private readonly IGraphics _graphics;

    public BoxDrawVisitor(IGraphics graphics)
    {
        _graphics = graphics;
    }

    public void Visit(Box to)
    {
        _graphics.DrawBox(to.Side);
    }

    public void Dispose()
    {
    }
}
This one is simple, giving Box instance we can call some magic operation on IGraphics interface which will draw the data on the device. Nice things starts here where it is needed to iterate on shapes inside the canvas:

class CanvasDrawVisitor : IVisitor<Canvas>
{
    private readonly IGraphics _graphics;
    private readonly IVisitor<Shape> _visitor;

    public CanvasDrawVisitor(IVisitor<Shape> visitor, IGraphics graphics)
    {
        _visitor = visitor;
        _graphics = graphics;
    }

    public void Visit(Canvas to)
    {
        _graphics.DrawRectangle(to.Height, to.Width);

        foreach (Shape shape in to)
        {
            shape.Accept(_visitor);
        }
    }

    public void Dispose()
    {
    }
}
Basically, canvas is an composition of shapes, and it is necessary to visit all of them. It may end up with coupling of different visitors implementations. To prevent it IVisitor<Shape> is introduced here. It’s kind of “abstract” visitor which should know which concrete visitor should be used based on the concrete type of the shape we got in the foreach loop. This “abstract” visitor is the resolution of the problem, so how it can be implemented? Before going there let’s see how this concept can be used in this Unit Test as an example:
[TestMethod]
public void TestDrawBox()
{
    Box b = new Box {Side = 5};

    IVisitor<Shape> visitor = _container.Resolve<IVisitor<Shape>>("Draw");

    b.Accept(visitor);
            
    A.CallTo(() => _graphics.DrawBox(5)).MustHaveHappened();
}
To apply some operation one can resolve visitor from the container which is capable to deal with virtually any shape while its concrete visitor is registered within the container. I decided to use registration names to distinguish visitors for the same objects but implementing different functionality:

[TestMethod]
public void TestDrawBox()
{
    Box b = new Box {Side = 5};

    IVisitor<Shape> visitor = _container.Resolve<IVisitor<Shape>>("Draw");

    b.Accept(visitor);
            
    A.CallTo(() => _graphics.DrawBox(5)).MustHaveHappened();
}

OK, we have a container defined with visitors implementations for every concrete shape type. But wait, what about this “abstract” visitor, isn't it registered as well? As you may already guessed VisitorContainerExtension is responsible for creating it. 

public class VisitorContainerExtension<T> : UnityContainerExtension
{
    protected override void Initialize()
    {
        Context.Strategies.AddNew<VisitorBuilderStrategy<T>>(UnityBuildStage.PreCreation);
    }
}

internal class VisitorBuilderStrategy<T> : BuilderStrategy
{
    public override void PreBuildUp(IBuilderContext context)
    {
        Type typeToBuild = context.BuildKey.Type;
        if (typeToBuild.IsGenericType && typeof (IVisitor<>).MakeGenericType(typeof(T)) == typeToBuild)
        {
            AbstractVisitor<T> abstractVisitor = new AbstractVisitor<T>(context);

            context.Existing = abstractVisitor;

            context.AddResolverOverrides(new DependencyOverride(typeToBuild, abstractVisitor));
        }
    }
}
Every time IVisitor<Shape> will be resolved on the unity container AbstractVisitor<Shape> instance will be created with current build context and this instance will be added to the resolution context to prevent creation of additional instance in case some class implementation depends on IVisitor<Shape>. This is the case for CanvasDrawVisitor for example. Thus, going back to the test above, the resolution line 

IVisitor<Shape> visitor = _container.Resolve<IVisitor<Shape>>("Draw");

will create instance of AbstractVisitor<Shape> thanks to VisitorBuilderStrategy which is registered on container. The last thing we have to see is the AbstractVisitor class implementation:

class AbstractVisitor<T> : IVisitor<T>
{
    private readonly IBuilderContext _context;
        
    public AbstractVisitor(IBuilderContext context)
    {
        _context = context;
    }

    public void Visit(T to)
    {
        Type concreteShapeType = to.GetType();

        // Construct generic visitor type for concrete shape type
        Type concreteVisitorType = typeof(IVisitor<>).MakeGenericType(concreteShapeType);

        object concreteVisitor = _context.NewBuildUp(new NamedTypeBuildKey(concreteVisitorType, _context.BuildKey.Name));

        try
        {
            // Invoke
            concreteVisitorType.InvokeMember("Visit", BindingFlags.InvokeMethod, null, concreteVisitor, new object[] { to });
        }
        catch(TargetInvocationException ex)
        {
            throw ex.InnerException;
        }
           
    }

    public void Dispose()
    {
    }
}
Here Visit method receives the concrete shape type which should be visited. The only thing AbstractVisitor should do is to resolve the registered concrete visitor implementation, like BoxDrawVisitor for instance, and delegate Visit call to the concrete visitor. For that meter concrete visitor type is constructed and then build context is used for construction which will preserve all ResolveOverride that you may provide to the initial resolve method call, like in test below. It is important to mention that initial BuildKey.Name is reused to resolve concrete visitors.

[TestMethod]
public void TestMagnifyAndThenDrawCircle()
{
    Circle c = new Circle {Radius = 5};

    var magnificationVisitor = _container.Resolve<IVisitor<Shape>>("Magnify", new ParameterOverride("ratio", 2D));
    var drawVisitor = _container.Resolve<IVisitor<Shape>>("Draw");

    c.Accept(magnificationVisitor, drawVisitor);

    A.CallTo(() => _graphics.DrawCircle(10)).MustHaveHappened();
}

Conclusion

In this article I showed how acyclic visitor may be implemented by using dependency injection container preventing coupling between visitors and downcast on Accept method implementations.

Source Code

The source code is licensed under Code Project Open License (CPOL) 1.02

Complete source code can be found here: https://github.com/parshim/AsyncVisitor.git

Enjoy!