The Last Visual Basic Developer Alive (I hope not)
Recently I’ve taken to reading books on software patterns. A few months ago I started the legendary “Design Patterns” aka “Gang of Four”. This is a classic and I highly recommend it. The book however discusses patterns in a very generic technical context and at that time I needed a book more about domain layer design so I took a break and picked up “Domain-Driven Design” which I also highly recommend. I finished that book a few weeks back and it shed a lot of light on some of the philosophical qualms I was battling at the time. I have since concluded my reading of Gang of Four and it was certainly worth it.
Working on the .NET platform, reading books from the C++/Smalltalk/Java dominated time period is amusing in that often such books emphasize some patterns which we take for granted in .NET because the infrastructure supports and encourages them so transparently. As an example, the Observer pattern (GoF) has been really simplified with .NET delegates and events, and the Mediator pattern (GoF) is almost a given in WinForms development. In some cases the CLR allows a more flexible and elegant implementation and this is true on other platforms where different constructs are given first-class status. In other cases it’s just cool to see how patterns are simply manifested in the framework e.g. Iterator (GoF) -> IEnumerable.
There was, however, one pattern which I’d been “waiting to read” since I set out that really ended up saving me on a technical challenge. Books like these on patterns are not necessarily required to be read sequentially but I like to get a thorough exposure to them so I don’t typically skip ahead. Comically this pattern was the very last one in the book: The Visitor pattern.
The Visitor pattern takes the common orientation of polymorphism and turns it on its side. For example let’s talk about persisting objects to some durable storage.
One approach to this is to give responsibility to domain objects for persisting themselves. Your domain base class will declare operations for Saving and Deleting instances from a persistent store and each subclass, having intimate knowledge of its own persistence needs and the database schema can override these to work correctly so that clients needn’t concern themselves with the concrete type of the object being persisted. This is both simple and effective.
I used to default to this methodology myself. Then our Chief Solutions Architect, Micah Swigert, turned me on to the idea of externalizing persistence from domain objects entirely. This opens up interesting possibilities and solves particular problems – e.g. multiple persistence mechanisms and stores can be supported without having to modify objects to support them. However, it reintroduces the problem of a persistence service being able to persist an object correctly based on its concrete type. I became aware of this issue when a co-worker encountered a bug in an application wherein a list of objects was being deleted from the database by a parent object. These objects actually came in two varieties, one of which had its own child objects which in turn needed to be deleted. The code wasn’t taking advantage of polymorphism and as such was littered with If TypeOf item Is … Then blocks to ensure proper handling. This was being applied on Saving but not Deleting and Foreign Key violations were popping up all over. I argued that these blocks should be refactored immediately and that objects should know how to delete themselves and where applicable their child objects without such type checking by client code (even if that client is a parent object). The refactoring cleared up the problem and the code. But it was only possible because responsibility for persistence was assigned to the objects themselves so how, I asked, would I have resolved this issue in my own style of design whereby objects and object graphs are persisted by external services without resorting to type checking?
Enter the Visitor Pattern. The structure of the pattern as described in Gang of Four is to define a base Visitor interface with one method for acting on each concrete type to be “visited”. I know this is a contrived example but it has to be to be simple. Visitor is actually a pattern I think is rarely needed, usually in a non-trivial system, but when needed can be a powerful tool.
Interface OrderVisitor
Sub VisitSimpleOrder(order As SimpleOrder)
Sub VisitMultilineOrder(order As MultilineOrder)
End Interface
Each class then has an Accept method which takes a visitor instance and calls the method pertaining to its own type on the visitor thus facilitating the correct behavior for the object’s concrete type to be invoked without putting this behavior inside the objects themselves.
MustInherit Class Order
MustOverride Sub Accept(visitor As OrderVisitor)
End Class
Class SimpleOrder : Inherits Order
Overrides Sub Accept(visitor As OrderVisitor)
visitor.VisitSimpleOrder(Me)
End Sub
End Class
Class MultilineOrder : Inherits Order
Overrides Sub Accept(visitor As OrderVisitor)
visitor.VisitMultiLineOrder(Me)
End Sub
End Class
With such an implementation you could declare a DeletingVisitor which calls the proper Stored Procedure(s) to delete objects or a SavingVisitor which knows to save MultilineOrders’ child LineItems correctly based on its type, without using If TypeOf … ElseIf TypeOf trees. This is especially important if you’re using the any of the Table Inheritance patterns.
Some advantages to this are that you can add new operations without defining a new MustOverride method in your base classes, which would break every concrete object; and that all of the logic for an operation is now centralized in the concrete visitor, not littered about all of the concrete classes which must be supported. The disadvantage to this pattern is that in order to support a new concrete class to be visited you must add a new MustOverride method to your visitor base class which will break every existing concrete visitor. As such it’s a good pattern when you want the flexibility to support new operations on a stable hierarchy.
In my case this is just the tradeoff I want. My system must be able to persist all known objects and I could potentially add different persistent stores: Relational Database, XML, serialization over the wire, etc.
This being .NET of course, there are some revisions to this implementation I’m looking at. For example, to get rid of this monolithic interface declaring all supported types:
Interface IVisitor
Sub Visit(obj As Object)
End Interface
Interface IVisitor(Of T) : Inherits IVisitor
Sub Visit(obj As T)
End Interface
Interface IVisitable
Sub Accept(visitor As IVisitor)
End Interface
This allows me to reuse my visitor interface generically across object hierarchies. A visitor will implement the generic IVisitor interface for all supported types. Potentially dangerous is when adding a new supported type existing visitors won’t break at compile time (enter automated testing). I’ve included in the base IVisitor definition an object based method to catch unsupported objects to allow a fallback mechanism, logging, or maybe even just throwing an exception. Another implementational question is how overriding is handled – if a visitor doesn’t explicitly support a concrete type should it failover to its parent type … all the way to Object? Or should it just break? The former can result in loss of data but may be desirable in some scenarios.
Be on the lookout for more of these pattern posts. I’ve just started “Patterns of Enterprise Application Architecture” and it looks good. And I’ve already enqueued “Refactoring” after that. Cheers!
September 30, 2007
·
Anthony D. Green ·
No Comments
Tags: design patterns · Posted in: Uncategorized

Leave a Reply