1 / 28

Visitor Pattern

Visitor Pattern. Functional Decomposition in OO via double dispatching. Before (1): 2 operations ‘ visit ’ a set. int main() //need abstract class Color… { Color *set[] = { new Red, new Blu, new Blu, new Red, new Red, 0 }; for (int i = 0; set[i]; ++i)

huntt
Download Presentation

Visitor Pattern

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Visitor Pattern Functional Decomposition in OO via double dispatching

  2. Before (1): 2 operations ‘visit’ a set int main() //need abstract class Color… { Color *set[] = { new Red, new Blu, new Blu, new Red, new Red, 0 }; for (int i = 0; set[i]; ++i) { set[i]->count(); //increment count of reds or count of blues set[i]->call(); // call for red calls eye(), and for blue sky() } Color::report_num(); } Expected output Red::eye Blu::sky Blu::sky Red::eye Red::eye Reds 3, Blues 2

  3. Before (2): call() and count() on colors Class Color { public: virtual void count() = 0; virtual void call() = 0; static void report_num() { cout << "Reds " << s_num_red << ", Blues " << s_num_blu << '\n'; } protected: static int s_num_red, s_num_blu; }; int Color::s_num_red = 0; int Color::s_num_blu = 0;

  4. Before (3) class Red: public Color { public: void count() { ++s_num_red; } void call() { eye(); } void eye() { cout << "Red::eye\n”; } }; class Blu: public Color { public: void count() { ++s_num_blu; } void call() { sky(); } void sky() { cout << "Blu::sky\n”; } }; Ie you ‘pollute’ Red and Blu with count and call… and static variables and a method

  5. After (1) The Color hierarchy specifies a single “accept()” method, and then the previous “count()” and “call()” methods are implemented as derived classes of Visitor . When accept() is called on a Color object, that is the first dispatch. When visit() is called on a Visitor object, that is the second dispatch; and the right method call can be done based on the type of both objects. Class Color { public: virtual void accept() = 0; };

  6. After (2) class Red: public Color { public: /* virtual */ void accept(Visitor*); //definition to follow void eye() { cout << "Red::eye\n”; } }; class Blu: public Color { public: /* virtual */ void accept(Visitor*); //definition to follow void sky() { cout << "Blu::sky\n”; } };

  7. After (3) class Visitor { public: virtual void visit(Red*) = 0; virtual void visit(Blu*) = 0; }; class CountVisitor: public Visitor { public : CountVisitor() { m_num_red = m_num_blu = 0; } /*virtual*/ void visit(Red*) { ++m_num_red; } /*virtual*/ void visit(Blu*) { ++m_num_blu; } void report_num() { cout << "Reds " << m_num_red << ", Blus " << m_num_blu << '\n’; } private: int m_num_red, m_num_blu; };

  8. After (4) class CallVisitor: public Visitor { public: /*virtual*/ void visit(Red *r) { r->eye(); } /*virtual*/void visit(Blu *b) { b->sky(); } }; void Red::accept(Visitor *v) { v->visit(this); } void Blu::accept(Visitor *v) { v->visit(this); }

  9. After (5) int main() { Color *set[] = { new Red, new Blu, new Blu, new Red, new Red, 0}; CountVisitor count_operation; CallVisitor call_operation; for (int i = 0; set[i]; i++) { set[i]->accept(&count_operation); set[i]->accept(&call_operation); } count_operation.report_num(); } Red::eye Blu::sky Blu::sky Red::eye Red::eye Reds 3, Blus 2 now let’s look at a Java example

  10. Decomposition • How to break up the functionality of program into • Modules • Packages • Classes • Methods • Statements • ….

  11. Two Popular Types of Decomposition • Two most prevalent • Object-Oriented Decomposition • Units of decomposition are objects that implement functions • Data should be encapsulated and thus easy to change • Designing and extending interfaces is key • Functional Decomposition • Units of decomposition are functions

  12. Functional Decomposition

  13. Functional Decomposition : easier said than done!!!

  14. Functional Decomposition:Abstract Example

  15. Tyranny of the Dominant Decomposition • All decompositions favor some types of changes at the expense of others • This is known as “The Tyranny of the Dominant Decomposition”

  16. Visitor Pattern: Document Example

  17. Document Example • Want to add new data processing ‘features’ • Word Count • Convert document to XML format • Spell check • etc…

  18. Two Approaches to this example • Object-Oriented Decomposition • Each feature is implemented by adding a new method to each document element • Functional Decomposition • Each feature is a class with methods for each kind of document element

  19. Object-Oriented Decomposition

  20. Here is the Functional Decompositionin the pattern class WCVisitor implements Visitor { //Each visit method deals with a specific concrete class public void visit(DocChar docChar) { … } public void visit(Document doc) { … } public void visit(Paragraph para) { … } public void visit(LineOfText lot) { … } }

  21. Visitor Pattern: Forces • There are a variety of features (i.e., functions) that can be applied on an object structure • e.x. Word Count, XML Conversion, Spell checking, etc. • The object structure is composed of objects that belong to different classes • The more classes, the more likely Visitor is the best choice

  22. Visitor Pattern for example JP: yes this is NOT easy to understand…

  23. Visitor Pattern: Double Dispatch • accept(Visitor) is called on an object • Dispatches to the right element class • visit(this) is called on the visitor • Dispatches to the right visitor class • accept(Visitor) is called on all children (fields) of the element • Causes a traversal over the object graph • e.g., sequence, depth first, breadth first, etc..

  24. accept Method Implementation class Document extends CompositeDocumentElement { DocumentElement[ ] children; //Other details of class are omitted public void accept(Visitor v) { v.visit(this); for(int i=0;i<children.length;i++) children[i].accept(v); // optionally: v.endVisit(this); as in the XML visitors } }

  25. visit Method Implementation class WCVisitor implements Visitor { int wc = 0; boolean wordDivider= false; public void visit(Document d) { wordDivider= true; } // similar methods are omitted public void visit(DocChar char) { if(char.isWhiteSpace()) { wordDivider= true; } else { if(wordDivider) { wc++; } else { wordDivider = false; } } } }

  26. XML Visitor Example class XMLVisitor implements Visitor { int indent = 0; //Other methods are omitted public void visit(Document doc) { indent(); indent += 2; System.out.println(“<document>”); } public void endVisit(Document doc) { indent(); System.out.println(“</document>”); index -= 2; } public void indent() { for(int i=0;i<=indent;i++) System.out.print(““); } }

  27. Visitor Pattern: UML class diagram

  28. Visitor Pattern: Scenario * • Step 1.2 is repeated for all “children” (or successor nodes) • of an element in the object graph (and repeated recursively) until some • termination criteria is reached (e.x. leaves of a tree structure) • JP: I include this slide to discuss later the limitations of this diagram!!

More Related