Presentation is loading. Please wait.

Presentation is loading. Please wait.

Behavioral Pattern: Visitor C h a p t e r 5 – P a g e 224 When an algorithm is separated from an object structure upon which it operates, new operations.

Similar presentations


Presentation on theme: "Behavioral Pattern: Visitor C h a p t e r 5 – P a g e 224 When an algorithm is separated from an object structure upon which it operates, new operations."— Presentation transcript:

1

2 Behavioral Pattern: Visitor C h a p t e r 5 – P a g e 224 When an algorithm is separated from an object structure upon which it operates, new operations can be added to existing object structures without modifying those structures The Visitor Pattern allows new virtual functions to be added to a family of classes without modifying the classes themselves; instead, one creates a visitor class that implements all of the appropriate specializations of the virtual function. This is particularly useful when there are a large number of instances of a small number of classes and some operation must be performed that involves all or most of them. (While powerful, the Visitor Pattern is more limited than conventional virtual functions since it isnt possible to create visitors for objects without adding a small callback method inside each class and the callback method in each of the classes is not inheritable.)

3 The Visitor Pattern C h a p t e r 5 – P a g e 225 The Visitor declares a visit operation for each class of ConcreteElement in the object structure. The operation's name and signature identifies the class that sends the Visit request to the visitor. That lets the visitor determine the concrete class of the element being visited. Then the visitor can access the elements directly through its particular interface. The ConcreteVisitor implements each operation declared by the Visitor. Each operation implements a fragment of the algorithm defined for the corresponding class or object in the structure. The ConcreteVisitor provides the context for the algorithm and stores its local state. This state often accumulates results during the traversal of the structure. The Element defines an Accept operation that takes a visitor as an argument, while the ConcreteElement implements an Accept operation that takes a visitor as an argument. The Object Structure can enumerate its elements and may provide a high-level interface to allow the visitor to visit its elements. It may either be a Composite (pattern) or a collection such as a list or a set.

4 C h a p t e r 5 – P a g e 226 Non-Software Example: Cab-Calling When a person calls a taxi company he or she becomes part of the company's list of customers (the ObjectStructure). The taxi companys dispatcher (the Client) then sends a cab (the Visitor) to the customer (the Element). Upon entering the taxi, the customer is no longer in control of his or her own transportation, the taxi (i.e., the taxi driver) is.

5 C h a p t e r 5 – P a g e 227 Software Example: Car Parts The Car (ObjectStructure) is composed of various CarElements (Wheels, Engine, Body). The CarElementVisitor provides an interface for visiting each type of CarElement. The DiagnosticVisitor and the TestDriveVisitor implement specific algorithms for dealing with the Cars CarElements without altering the definitions of the Car or the CarElements.

6 C h a p t e r 5 – P a g e 228 Car Parts Visitor Pattern C++ Code #include using namespace std; class Wheel; class Engine; class Body; class Car; // Interface to all car parts struct CarElementVisitor { virtual void visit(Wheel& wheel) const = 0; virtual void visit(Engine& engine) const = 0; virtual void visit(Body& body) const = 0; virtual void visitCar(Car& car) const = 0; virtual ~CarElementVisitor() {} }; // Interface to one car part struct CarElement { virtual void accept(const CarElementVisitor& visitor) = 0; virtual ~CarElement() {} };

7 C h a p t e r 5 – P a g e 229 // Wheel element, there are four wheels with unique names class Wheel : public CarElement { public: explicit Wheel(const string& name) : name(name) {} const string& getName() const { return name; } void accept(const CarElementVisitor& visitor) { visitor.visit(*this); } private: string name; }; // Engine element class Engine : public CarElement { public: void accept(const CarElementVisitor& visitor) { visitor.visit(*this); } }; // Body element class Body : public CarElement { public: void accept(const CarElementVisitor& visitor) { visitor.visit(*this); } };

8 C h a p t e r 5 – P a g e 230 // Car, all car elements (parts) together in one vector class Car { public: vector & getElements() { return elements; } Car() { // assume that neither push_back nor Wheel(const string&) may throw elements.push_back( new Wheel("front left") ); elements.push_back( new Wheel("front right") ); elements.push_back( new Wheel("back left") ); elements.push_back( new Wheel("back right") ); elements.push_back( new Body() ); elements.push_back( new Engine() ); } ~Car() { vector ::iterator it; for (it = elements.begin(); it != elements.end(); ++it) { delete *it; } private: vector elements; };

9 C h a p t e r 5 – P a g e 231 // DiagnosticVisitor adds a diagnostic capability to the // Car class without modifying the Car class itself. class CarElementDiagnosticVisitor : public CarElementVisitor { public: void visit(Wheel& wheel) const { cout << "Testing the car's " << wheel.getName() << " wheel for tread and punctures" << endl; } void visit(Engine& engine) const { cout << "Examining the car's engine for leaks and loose belts" << endl; } void visit(Body& body) const { cout << "Examining the car's body for dents and scratches" << endl; } void visitCar(Car& car) const { cout << "Performing diagnostic testing on the car" << endl; vector & elems = car.getElements(); // Cycle through the car's elements, issuing a // callback from each car element to this visitor. vector ::iterator it; for (it = elems.begin(); it != elems.end(); ++it ) { (*it)->accept(*this); } cout << "Diagnostic testing complete" << endl << endl; } };

10 C h a p t e r 5 – P a g e 232 // TestDriveVisitor adds a test drive capability to the // Car class without modifying the Car class itself. class CarElementTestDriveVisitor : public CarElementVisitor { public: void visit(Wheel& wheel) const { cout << "Kicking the car's " << wheel.getName() << " tire" << endl; } void visit(Engine& engine) const { cout << "Starting the car's engine" << endl; } void visit(Body& body) const { cout << "Driving the car for a road test" << endl; } void visitCar(Car& car) const { cout << "Test driving the car" << endl; vector & elems = car.getElements(); // Cycle through the car's elements, issuing a // callback from each car element to this visitor. vector ::iterator it; for (it = elems.begin(); it != elems.end(); ++it ) { (*it)->accept(*this); } cout << "Test drive complete" << endl << endl; } };

11 C h a p t e r 5 – P a g e 233 void main() { Car car; CarElementDiagnosticVisitor printVisitor; CarElementTestDriveVisitor doVisitor; printVisitor.visitCar(car); doVisitor.visitCar(car); }

12 Visitor Pattern Advantages C h a p t e r 5 – P a g e 234 The Visitor Pattern permits the addition of functions to class libraries for which either the source code or the ability to change the source code is unavailable. This pattern is also helpful when it is necessary to obtain data from a disparate collection of unrelated classes and use it to present the results of a global calculation to the user program. It can be used to gather related operations into a single class rather than forcing the designer to change or derive classes to add these operations.


Download ppt "Behavioral Pattern: Visitor C h a p t e r 5 – P a g e 224 When an algorithm is separated from an object structure upon which it operates, new operations."

Similar presentations


Ads by Google