Chain of Responsibility
Visitor Design Pattern
In OOPS and software engineering, a way of separating an algorithm from an object structure it operates on is the visitor design pattern. One of the practical result of this separation is the ability to add new operations to existing object structures without modifying the original structures. It is one way to easily follow the open/closed principle. Now a days Collections are data types widely used in object oriented programming. Often collections contain some objects of different types and in those cases sometimes operations have to be performed on all the collection elements without knowing the datatype. A feasible approach to apply a specific operation on objects of different types in a collection would be the use if blocks in conjunction with 'instanceof' for each element. This approach is not a good one, not flexible and not object oriented at all. At this point of time we should think to the Open Close principle and we should remember from there that we can replace if blocks with an abstract class and each concrete class will implement its own operation.
Applicability & ExamplesThe visitor pattern is used when:
Example 1 - Customers Application.We want to create a reporting module in our application to make statistics about a group of customers. The statistics should made very detailed so all the data related to the customer must be parsed. All the entities involved in this hierarchy must accept a visitor so the CustomerGroup, Customer, Order and Item are visitable objects. In the example we can see the following actors:
Specific problems and implementation
Tight Coupled Visitable objects
The classic implementation of the Visitor pattern have a major drawback because the type of visitor methods has to be known in advance. The Visitor interface can be defined using polymorphic methods or methods with different names:
However this type should be known in advance. When a new type is added to the structure a new method should be added to this interface and all existing visitors have to be changed accordingly. A pair method is written in the concrete Visitable objects:
It doesn't really matters if the polymorphic methods with the same name but different signatures are used or not, because in either way the type is known at compile time sot for each new visitable object this method must be implemented accordingly. The main advantage of the fact that new visitors can be easily added is compensated by the fact that the addition of new visitable objects is really hard.
Visitor Pattern using ReflectionReflection can be used to overcome the main drawback of the visitor pattern. When the standard implementation of visitor pattern is used the method to invoke is determined at runtime. Reflection is the mechanism used to determine the method to be called at compile-time. This way the visitable object will use the same code in the accept method. This code can be moved in an abstraction so the IVisitable interface will be transformed to an advanced class.
Let's take our example. We need to add a new visitable class in our structure, called Product. We should modify the IVisitor interface to add a visitProduct method. But changing an interface is one of the worth things that can be done. Usually, interfaces are extended by lots of classes changing the interface means changing the classes. Maybe we have lots of visitors but we don't want to change all of them, we need only another report.
In this case we start from the idea that we should keep the interface unchanged. The solution is to replace the interface with an abstract class and to add an abstract method called defaultVisit. The defaultVisit will be implemented by each new concrete visitor, but the interface and old concrete visitors will remain unchanged.
The code is very simple: the
Another point that should be marked is the defaultVisit method: We should visit only classes we know:
Statefull VisitorsThe visitors objects can be complex objects and can maintain a context during a traversal.
Encapsulation of visitable objectsThe behavior is defined in the visitor itself and the objects structure is represented by visitable objects. The Visitor needs to access data kept by visitable objects so practically the pattern forces to expose from visitable objects the data required in the visitor, using public methods.
Visitors and IteratorsThe iterator pattern and visitor pattern has the same benefit, they are used to traverse object structures. The main difference is that the iterator is intended to be used on collections. Usually collections contain objects of the same type. The visitor pattern can be used on complex structure such as hierarchical structures or composite structures. In this case the accept method of a complex object should call the accept method of all the child objects.
Another difference is operation performed on the objects: In one case the visitor defines the operations that should be performed, while the iterator is used by the client to iterate through the objects form a collection and the operations are defined by the client itself.
Visitors and CompositesThe visitor pattern can be used in addition with the composite pattern. The object structure can be a composite structure. In this case in the implementation of the accept method of the composite object the accept methods of the component object has to be invoked.