Let’s talk about the visitor design pattern. This one is tough to find a real-world analog for, but once it clicks for you it can be really useful.
Basically the visitor pattern is used when you want to add functionality to an object or a set of objects without changing the object itself. If you have a list of objects and you want to perform a particular calculation on each one and might need to add more calculations later, you would use the visitor to ‘visit’ each one, get its state, and do the calculation. Headfirst design patterns uses the example of a menu item and an ingredient both needing a nutrition information report. It’s ugly to add essentially the same method to two classes and it violates the single responsibility principle to add a method that does something the base object shouldn’t know about.
Uncle Bob uses the example of building a report with data from hourly but not salaried employee objects. The employee object shouldn’t know anything about how to generate a line for that report or even whether it should be on the report at all, so it’s much cleaner to use a visitor to get each object’s data and use that to build the report.
So how does the visitor pattern actually work? First of all you need some interfaces or abstract classes for your other classes to inherit from. To keep using Uncle Bob’s employee example, you need an employee interface with an accept method that takes a visitor interface/base class as a parameter. Your visitor interface needs a visit method for each type of object it’s going to visit. Now that you have your interfaces set up, concrete employee classes like SalaryEmployee and HourlyEmployee can implement the accept method. All you need to do there is call visit(this) on the visitor that was passed in. Your concrete visitor class just needs to implement visit methods for each visited object and you’re done! There’s a nice clean class diagram here in case seeing it makes it easier to understand.
Why so many interfaces? Wouldn’t it be simpler just to call methods on the concrete objects directly? Not so much. We need an accept method on the employee interface so that the code that iterates over your list of employees and calls accept(visitor) on each one doesn’t have to know what type of employee it is. We need a visitor interface separate from the concrete class/es so that we can add more visitors without having to change the visited objects and because the visited objects shouldn’t be coupled to the visitor object. In the report example, the employee objects shouldn’t know anything about the visitor that compiles the report. To put the single responsibility principle another way, the report just isn’t any of the employee object’s business. If we decide to change the way that report is calculated or add another version of it, the employee object shouldn’t know or care.
Why not put the accept(visitor) method in the employee base class? Because then it would only be able to pass an Employee to the visitor, which is no good if different types of employees need to be treated differently. Yes, it’s duplicate code, but only a tiny little of it and in this case it’s necessary.
Aside from keeping your base objects from having multiple responsibilities, another thing the visitor pattern gives you is one class where all the related methods live. To stick with the report example a little longer, we’ve got all our report logic in one place instead of scattering it over different classes. Yay single responsibility! If we decide to change how we calculate rows in that report, we only have to change one class. If we only have two types of employees that may not sound like a big gain, but what if we need to add contractors and consultants and seasonal employees and part time employees?
The visitor pattern is a really weird concept at first but once you understand it, it can make your code a lot cleaner.