Visitor – A Dramatization

The Reference for this pattern is ‘Design Patterns: Elements of Re-Usable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides, or GOF, for short. Note that the question of what is a pattern is a subject of considerable discussion and some dispute. Some say that what GOF contains are not patterns but ‘micro architectures’. In any case, what it is important to recognize is that it is not the implementation detail that is important: to distinguish a pattern requires a deeper appreciation than this. So although GOF contains example ( C++) code this should be regarded essentially as a helpful aid in identifying the underlying pattern.

This dramatization of the Visitor is the result of a working bee involving Darius Zakrzewski, Andy Bulka and Don Macrae in the context of the Melbourne Patterns Group. Its purpose is to communicate the essential structure of the Visitor pattern in a way which is easily accessible and programming language independent. There may not be much point in actually staging this ‘play’, but experience so far has suggested that a ‘play reading’ of the script and a discussion is effective in giving first-timers an understanding of the pattern.

The Cast of Characters

The Fat Controller. The Master-of-Ceremonies. Kicks off the action. Acts as link man. Finishes things off. Mr Big. Sometimes is the Client.
Members of the DwellingElementFamily:
All members of the DwellingElement family accept as visitors members of the DwellingVisitor family, no questions asked. The whole family is congenitally blind, and can’t tell one member of the DwellingVisitor family from another.
House1 A house. A member of the DwellingElement family.
Office1 Another member of the DwellingElement family
House2 And another.
Members of the DwellingVisitorFamily
These visitor guys/gals know their way around all of the members of the DwellingElement family, but they’re a bit slow on the uptake: they don’t know which member of the family has accepted them in until they’re told by each member to DO something specificically to that member.
CleaningLady A cleaning lady. Member of the DwellingVisitor family. Knows how to clean all sorts of dwellings.
MaintenanceMan Another member of the DwellingVisitor family. Knows how to do all regular maintenance in all members of the DwellingFamily.

Script

Character Dialogue   Indicative code
  The FatController is seated centre rear. The DwellingElements are standing together, front right, facing the audience. The CleaningLady and the Maintenance Lady are standing rear left, with their backs to the audience.
FatController Good evening. I am the FatController. I am responsible for these DwellingElements here. ( gestures towards them ). I have just been asked to get them all cleaned, and to get the routine maintenance done. But first, I’ll allow them to introduce themselves.    
House1 Hello. I am House1. I am a house, and a member of the DwellingElement family.   THouse = class( TDwellingElement)
Office Hello. I am Office. I am not a house, but I too am a member of the DwellingElement family.   TOffice = class( TDwellingElement)
House2. Hi. House2 here. Ditto.    
FatController Well, now that’s done, let’s get on with business. First, to the cleaning. ( calls to cleaning lady ) Hey, CleaningLady! WakeUp, you’re needed! Or more to the point.   CleaningLady := TCleaningLady.Create

{ TCleaningLady = class( TVisitor) }

CleaningLady ( Turns around and moves front left. ) You called, boss?    
FatController Yes, I did. I’m arranging for you to visit that dwellingelement over there. In fact, here goes with the magic words:

CleaningLady moves beside House1, both looking towards the audience.

( To audience ) In case you hadn’t noticed, I just invoked House1’s ‘AcceptVisitor’ method, which expects a member of the DwellingVisitor family as a parameter.

You may know that this is the first step in what GOF refers to as a ‘double dispatch’ mechanism. All DwellingElements have an AcceptVisitor method, in fact it’s declared in the base class as a pure virtual (i.e. declared but not implemented, the subclasses MUST implement the pure virtual), but the particular AcceptVisitor method which has been called in this case belongs to a house.

  House1.AcceptVisitor( CleaningLady )
House1 Oo! A visitor! I don’t know what kind of visitor it is, I just know its from an acceptable family: the DwellingVisitor family. They’re all just devoted to us DwellingElements. But they’re a bit slow, so I need to tell him that I’m a house, and not an office or any other kind of DwellingElement, so’s he’ll be able to find his way around. All I have to do is invoke his VisitHouse method, passing myself as a parameter. (to audience - if I were an office, I would have called his VisitOffice method.)   Visitor.VisitHouse( Self )
FatController ( To audience ) That of course was the second step in the ‘double dispatch’ process: it was the CleaningLady’s VisitHouse method which was invoked by House1, and not her VisitOffice or Visit any other member of my family method.

At the abstract level we have a DwellingVisitor visting a DwellingElement. At the concrete level we have a CleaningLady visiting a house.

   
CleaningLady So I'm cleaning a house. I know I'm cleaning a house because I'm executing my .visitHouse method.

I know that first I need to clean the house's sitting room.

  CleanSittingRoom( House.GetSittingRoom )

etc. etc.

  Next I must clean the kitchen.   CleanKitchen( House.GetKitchen )
  And I finish with the bedroom ( it’s a small house )   CleanBedroom( House.GetBedroom )
  ( Calling out to the FatController ) Hey boss! Finished this house you sent me to!    
FatController Thanks dear. Your next job is to visit another dwelling element, over there. ( The FatController gestures towards Office).

CleaningLady moves from House1 to Office.

( To audience ) This time I invoked Office’s ‘AcceptVisitor’ method, which of course also expects a member of the DwellingVisitor family as a parameter.

  Office.AcceptVisitor( CleaningLady )
Office Oo! A visitor! I don’t know what kind of visitor it is, I just know it’s from an acceptable family: the DwellingVisitor family. I’ll just tell him that I’m an Office, and not a house or any other kind of DwellingElement, so’s he’ll be able to find his way around. Here goes:.

There! I’ve just invoked his VisitOffice method, and passed myself as a parameter.

  Visitor.VisitOffice( Self )
CleaningLady So, an Office. First I need to do the boadroom table with Mr Sheen:   PolishBoadroomTable(
Office.GetBoadroomTable )
  Next I’ll empty the waste paper baskets:   Empty( Office.GetWastePaperBaskets );
  Now, I’ll vacuum the carpet:   VacuumClean( Office.GetCarpet )
  ( Calling out to the FatController ) Hey boss! Finished this Office you sent me to!    
FatController Thanks cleaning lady. You are free to go.   CleaningLady.free
 

Scene II, the second Visitor

   
FatController Well, now lets do some maintenance. Hey, MaintenanceMan! WakeUp, you’re needed!   MaintenanceMan :=
TMaintenanceMan.Create
FatController Now MaintenanceMan, do some repair work on house1.   House1.AcceptVisitor( MaintenanceMan )
House1 Oo! A visitor! I don’t know what kind of visitor it is, & I need to tell him that I’m a house, and not an office or any other kind of DwellingElement, so’s he’ll be able to find his way around. All I have to do is invoke his VisitHouse method, (just like I did with the cleaningLady) passing myself as a parameter.   Visitor.VisitHouse( Self )
MaintenanceMan So I'm repairing a house. I know I'm repairing a house because I'm executing my .visitHouse method. First I'll check the lightbulbs… then I'll check the power switches in the house's bathroom …   for i := 1 to house.rooms.count -1 do
checkLightbulb( house.rooms[ i ] )
end

etc. etc.

  ( Calling out to the FatController ) Hey boss! Finished!    
FatController Ok thanks. The office buildings don't need maintenance this week, so that's it for today.   MaintenanceMan.free