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 cant 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 theyre a bit slow on the uptake: they dont know which member of the family has accepted them in until theyre 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, Ill 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 thats done, lets get on with business. First, to the cleaning. ( calls to cleaning lady ) Hey, CleaningLady! WakeUp, youre 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. Im
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 hadnt noticed, I just invoked House1s 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 its 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 dont know what kind of visitor it is, I just know its from an acceptable family: the DwellingVisitor family. Theyre all just devoted to us DwellingElements. But theyre a bit slow, so I need to tell him that Im a house, and not an office or any other kind of DwellingElement, sos hell 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
CleaningLadys 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 ( its 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 Offices AcceptVisitor method, which of course also expects a member of the DwellingVisitor family as a parameter. |
Office.AcceptVisitor( CleaningLady ) | |
| Office | Oo! A visitor! I
dont know what kind of visitor it is, I just know its from an acceptable
family: the DwellingVisitor family. Ill just tell him that Im an Office, and
not a house or any other kind of DwellingElement, sos hell be able to find his
way around. Here goes:. There! Ive 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 Ill empty the waste paper baskets: | Empty( Office.GetWastePaperBaskets ); | ||
| Now, Ill 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, youre needed! | MaintenanceMan := TMaintenanceMan.Create |
|
| FatController | Now MaintenanceMan, do some repair work on house1. | House1.AcceptVisitor( MaintenanceMan ) | |
| House1 | Oo! A visitor! I dont know what kind of visitor it is, & I need to tell him that Im a house, and not an office or any other kind of DwellingElement, sos hell 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 | |