{[ promptMessage ]}

Bookmark it

{[ promptMessage ]}

pattern-examples4

pattern-examples4 - OO Pattern Examples Case Studies Using...

Info iconThis preview shows page 1. Sign up to view the full content.

View Full Document Right Arrow Icon
This is the end of the preview. Sign up to access the rest of the document.

Unformatted text preview: OO Pattern Examples Case Studies Using Patterns Douglas C. Schmidt Object-Oriented Design Case Studies with Patterns & C++ Professor [email protected] www.dre.vanderbilt.edu schmidt Douglas C. Schmidt Department of EECS Vanderbilt University 615 343-8197 The following slides describe several case studies using C++ & patterns to build highly extensible software The examples include 1. Expression Tree e.g., Adapter, Factory, Bridge 2. System Sort e.g., Facade, Adapter, Iterator, Singleton, Factory Method, Strategy, Bridge 3. Sort Veri er e.g., Strategy, Factory Method, Facade, Iterator, Singleton Vanderbilt University 1 OO Pattern Examples Case Study: Expression Tree Evaluator Douglas C. Schmidt OO Pattern Examples Expression Tree Diagram Douglas C. Schmidt The following inheritance & dynamic binding example constructs expression trees Expression trees consist of nodes containing operators & operands Operators have di erent precedence levels, di erent associativities, & di erent arities, e.g., Multiplication takes precedence over addition The multiplication operator has two arguments, whereas unary minus operator has only one Operands are integers, doubles, variables, etc. We'll just handle integers in this example . . . _ UNARY NODE * + 5 3 INTEGER NODES BINARY NODES 4 4 Vanderbilt University 2 Vanderbilt University 3 use_ tag_ op_ num_ unary_ binary_ MEMORY LAYOUT Vanderbilt University Tree Node Vanderbilt University OO Pattern Examples OO Pattern Examples 1 1|2 CLASS RELATIONSHIPS Tree Node Expression trees Trees may be evaluated" via di erent traversals e.g., in-order, post-order, pre-order, level-order The evaluation step may perform various operations, e.g., Traverse & print the expression tree Return the value" of the expression tree Generate code Perform semantic analysis Here's the memory layout of a struct Tree Expression Tree Behavior Memory Layout of Algorithmic Version Node object Douglas C. Schmidt 6 OO Pattern Examples Douglas C. Schmidt 4 A typical algorithmic implementation use a switch statement & a recursive function to build & evaluate a tree, e.g., void print_tree Tree_Node *root switch root- tag_ case NUM: printf "d", root- num_; break; case UNARY: printf "s", root- op_ 0 ; print_tree root- unary_; printf ""; break; case BINARY: printf ""; print_tree root- binary_.l_; printf "s", root- op_ 0 ; print_tree root- binary_.r_; printf ""; break; default: printf "error, unknown type n"; Print Tree Function Do OO Pattern Examples A typical algorithmic method for implementing expression trees involves using a struct union to represent data structure, e.g., typedef struct Tree_Node Tree_Node; struct Tree_Node enum NUM, UNARY, BINARY tag_; short use_; * reference count * union char op_ 2 ; int num_; o; define num_ o.num_ define op_ o.op_ union Tree_Node *unary_; struct Tree_Node *l_, *r_; binary_; c; define unary_ c.unary_ define binary_ c.binary_ ; Algorithmic Version D Vanderbilt University Vanderbilt University OO Pattern Examples Limitations with Algorithmic Approach Douglas C. Schmidt OO Pattern Examples More Limitations with Algorithmic Approach Douglas C. Schmidt Problems or limitations with the typical algorithmic approach include Little or no use of encapsulation Incomplete modeling of the application domain, which results in 1. Tight coupling between nodes & edges in union representation 2. Complexity being in algorithms rather than the data structures e.g., switch statements are used to select between various types of nodes in the expression trees Compare with binary search! 3. Data structures are passive" & functions do most processing work explicitly The program organization makes it di cult to extend, e.g., Any small changes will ripple through the entire design & implementation e.g., see the ternary" extension below Easy to make mistakes switching on type tags . . . Solution wastes space by making worst-case assumptions wrt structs & unions This is not essential, but typically occurs Note that this problem becomes worse the bigger the size of the largest item becomes! Vanderbilt University 8 Vanderbilt University 9 OO Pattern Examples OO Alternative Douglas C. Schmidt OO Pattern Examples Expression Tree Diagram Douglas C. Schmidt Contrast previous algorithmic approach with an object-oriented decomposition for the same problem: Start with OO modeling of the expression tree" application domain, e.g., go back to original picture Discover several classes involved: class Node: base class that describes expression tree vertices: class Int Node: used for implicitly converting int to Tree node class Unary Node: handles unary operators, e.g., -10, +10, !a class Binary Node: handles binary operators, e.g., a + b, 10 - 30 class Tree: glue" code that describes expression-tree edges, i.e., relations between Nodes Note, these classes model entities in the application domain i.e., nodes & edges vertices & arcs Vanderbilt University 10 Vanderbilt University _ UNARY NODE * + 5 3 INTEGER NODES BINARY NODES 4 4 11 OO Pattern Examples Relationships Between Tree & Node Classes Binary Node Unary Node Int Node Douglas C. Schmidt OO Pattern Examples Design Patterns in the Expression Tree Program Douglas C. Schmidt 1 1 Ternary Node 1 2 3 1 Tree -a has Node Factory Centralize the assembly of resources necessary to create an object e.g., decouple Node subclass initialization from use Bridge Decouple an abstraction from its implementation so that the two can vary independently e.g., printing contents of a subtree and managing memory Adapter Convert the interface of a class into another interface clients expect e.g., make Tree conform C++ iostreams 12 Vanderbilt University 13 Vanderbilt University OO Pattern Examples class Tree; Forward declaration C++ Node Interface Douglas C. Schmidt OO Pattern Examples Describes the Tree vertices class Node friend class Tree; protected: Only visible to derived classes Node : use_ 1 * pure * virtual void print std::ostream & const = 0; Important to make destructor virtual! virtual ~Node ; private: int use_; Reference counter. ; include "Node.h" Bridge class that describes the Tree edges and acts as a Factory. class Tree public: Factory operations Tree int; Tree const string &, Tree &; Tree const string &, Tree &, Tree &; Tree const Tree &t; void operator= const Tree &t; ~Tree ; void print std::ostream & const; private: Node *node_; pointer to a rooted subtree C++ Tree Interface Douglas C. Schmidt Vanderbilt University 14 Vanderbilt University 15 OO Pattern Examples C++ Int Node Interface include "Node.h" class Unary_Node : public Node public: Unary_Node const string &op, const Tree &t; virtual void print std::ostream &stream const; private: string operation_; Tree operand_; ; Douglas C. Schmidt OO Pattern Examples C++ Unary Node Interface Douglas C. Schmidt include "Node.h" class Int_Node : public Node public: Int_Node int k; virtual void print std::ostream &stream const; private: int num_; operand value. ; Vanderbilt University 16 Vanderbilt University 17 OO Pattern Examples C++ Binary Node Interface Douglas C. Schmidt include "Node.h" Do Node Node PART PART tag tag operator_ operator op op left_ left (Tree PART)) (Tree PART middle_ middle (Tree PART)) (Tree PART right_ right (Tree PART)) (Tree PART Node Node PART PART operator_ operator left_ left (Tree PART)) (Tree PART Node Node PART PART operator_ operator operand_ operand (Tree PART)) (Tree PART vptr vptr Tree use_ use Unary Node right_ right (Tree PART)) (Tree PART node_ ptr Node Node Node PART PART num_ num Binary Node Memory Layout for C++ Version OO Pattern Examples Memory layouts for di erent subclasses of Node Int_Node Ternary Node Vanderbilt University 18 Vanderbilt University class Binary_Node : public Node public: Binary_Node const string &op, const Tree &t1, const Tree &t2; virtual void print std::ostream &s const; private: const string operation_; Tree left_; Tree right_; ; OO Pattern Examples C++ Int Node Implementations include "Unary_Node.h" Unary_Node::Unary_Node const string &op, const Tree &t1 : operation_ op, operand_ t1 void Unary_Node::print std::ostream &stream const stream "" this- operation_ this- operand_ recursive call! ""; Douglas C. Schmidt OO Pattern Examples C++ Unary Node Implementations Douglas C. Schmidt include "Int_Node.h" Int_Node::Int_Node int k: num_ k void Int_Node::print std::ostream &stream const stream this- num_; Vanderbilt University 20 Vanderbilt University 21 OO Pattern Examples C++ Binary Node Implementation Douglas C. Schmidt OO Pattern Examples Initializing the Node Subclasses Douglas C. Schmidt include "Binary_Node.h" Binary_Node::Binary_Node const string &op, const Tree &t1, const Tree &t2: operation_ op, left_ t1, right_ t2 void Binary_Node::print std::ostream &stream const stream "" this- left_ recursive call " " this- operation_ " " this- right_ recursive call ""; Problem How to ensure the Node subclasses are initialized properly Forces There are di erent types of Node subclasses e.g., take di erent number & type of arguments We want to centralize initialization in one place because it is likely to change . . . Solution Use a Factory pattern to initialize the Node subclasses Vanderbilt University 22 Vanderbilt University 23 OO Pattern Examples The Factory Pattern Douglas C. Schmidt OO Pattern Examples Structure of the Factory Pattern Factory make_product() creates Product product = ... return product Douglas C. Schmidt Intent Centralize the assembly of resources necessary to create an object Decouple object creation from object use by localizing creation knowledge This pattern resolves the following forces: Decouple initialization of the Node subclasses from their subsequent use Makes it easier to change or add new Node subclasses later on e.g., Ternary nodes . . . A generalization of the GoF Factory Method pattern Vanderbilt University 24 Vanderbilt University Product 25 OO Pattern Examples Using the Factory Pattern Douglas C. Schmidt OO Pattern Examples Printing Subtrees Douglas C. Schmidt The Factory pattern is used by the Tree class to initialize Node subclasses: Tree::Tree int num : node_ new Int_Node num Tree::Tree const string &op, const Tree &t : node_ new Unary_Node op, t Tree::Tree const string &op, const Tree &t1, const Tree &t2 : node_ new Binary_Node op, t1, t2 Problem How do we print subtrees without revealing their types? Forces The Node subclass should be hidden within the Tree instances We don't want to become dependent on the use of Nodes, inheritance, & dynamic binding, etc. We don't want to expose dynamic memory management details to application developers Solution Use the Bridge pattern to shield the use of inheritance & dynamic binding Vanderbilt University 27 Vanderbilt University 26 OO Pattern Examples The Bridge Pattern Douglas C. Schmidt OO Pattern Examples Structure of the Bridge Pattern 1: method_impl() Douglas C. Schmidt Intent Decouple an abstraction from its implementation so that the two can vary independently This pattern resolves the following forces that arise when building extensible software with C++ 1. How to provide a stable, uniform interface that is both closed & open, i.e., interface is closed to prevent direct code changes Implementation is open to allow extensibility 2. How to manage dynamic memory more transparently & robustly 3. How to simplify the implementation of operator Vanderbilt University 28 Abstraction method() Implementor method_impl() Concrete ImplementorA method_impl() Concrete ImplementorB method_impl() Vanderbilt University 29 OO Pattern Examples Using the Bridge Pattern 1: print() Douglas C. Schmidt OO Pattern Examples Illustrating the Bridge Pattern in C++ Douglas C. Schmidt Tree print() Node print() The Bridge pattern is used for printing expression trees: void Tree::print std::ostream &os const this- node_- print os; Int Node Ternary print() Binary Node Node Unary print() print() Node print() Note how this pattern decouples the Tree interface for printing from the Node subclass implementation i.e., the Tree interface is xed, whereas the Node implementation varies However, clients need not be concerned about the variation . . . Vanderbilt University 30 Vanderbilt University 31 OO Pattern Examples Integrating with C++ I O Streams Douglas C. Schmidt OO Pattern Examples The Adapter Pattern Douglas C. Schmidt Problem Our Tree interface uses a print method, but most C++ programmers expect to use I O Streams Forces Want to integrate our existing C++ Tree class into the I O Stream paradigm without modifying our class or C++ I O Solution Use the Adapter pattern to integrate Tree with I O Streams Intent Convert the interface of a class into another interface client expects Adapter lets classes work together that couldn't otherwise because of incompatible interfaces This pattern resolves the following force: 1. How to transparently integrate the Tree with the C++ istd::ostream operators Vanderbilt University 32 Vanderbilt University 33 OO Pattern Examples Structure of the Adapter Pattern 1: request () Douglas C. Schmidt OO Pattern Examples Using the Adapter Pattern 1: operator<< Douglas C. Schmidt client Target request() client Target operator<< Adapter request() Adaptee 2: specific_request() specific_request() 34 iostream operator<< 2: print() Tree print() Vanderbilt University Vanderbilt University 35 OO Pattern Examples Using the Adapter Pattern Reference counting via the counted body" idiom Tree::Tree const Tree &t: node_ t.node_ ++this- node_- use_; Sharing, ref-counting. Douglas C. Schmidt OO Pattern Examples C++ Tree Implementation Douglas C. Schmidt The Adapter pattern is used to integrate with C++ I O Streams std::ostream &operator std::ostream &s, const Tree &tree tree.print s; This triggers Node * virtual call via tree.node_- print s, which is implemented as the following: *tree.node_- vptr 1 tree.node_, s; return s; void Tree::operator= const Tree &t if this == &t return; order important here! ++t.node_- use_; --this- node_- use_; if this- node_- use_ == 0 delete this- node_; this- node_ = t.node_; Note how the C++ code shown above uses I O streams to adapt" the Tree interface . . . 36 Vanderbilt University Vanderbilt University 37 OO Pattern Examples C++ Tree Implementation cont'd Douglas C. Schmidt OO Pattern Examples Tree::~Tree Ref-counting, garbage collection --this- node_- use_; if this- node_- use_ = 0 delete this- node_; include istd::ostream.h include "Tree.h" C++ Main Program Douglas C. Schmidt int main int, char * const Tree t1 = Tree "*", Tree "-", 5, Tree "+", 3, 4; cout t1 endl; prints -5 * 3 + 4 const Tree t2 = Tree "*", t1, t1; prints -5 * 3 + 4 * -5 * 3 + 4. cout t2 endl; return 0; Destructors of t1 & t2 recursively delete entire tree when leaving scope. Vanderbilt University 38 Vanderbilt University 39 Do Binary Node Unary Node Int Node Do Binary Node Unary Node Expression Tree Diagram 1 Expression tree for t1 = -5 * 3 + 4 Expression Tree Diagram 2 Int Node 4 4 OO Pattern Examples OO Pattern Examples Vanderbilt University Expression tree for t2 = t1 * t1 print( ) print( ) + + 3 t2 * t1 * t1 * 5 3 OO Pattern Examples Adding Ternary Nodes Douglas C. Schmidt OO Pattern Examples Extending the existing program to support ternary nodes is straightforward i.e., just derive new class Ternary Node to handle ternary operators, e.g., a == b ? c : d, etc. include "Node.h" class Ternary_Node : public Node public: Ternary_Node const string &, const Tree &, const Tree &, const Tree &; virtual void print std::ostream & const; private: const string operation_; Tree left_, middle_, right_; ; include "Ternary_Node.h" Ternary_Node::Ternary_Node const string &op, const Tree &a, const Tree &b, const Tree &c : operation_ op, left_ a, middle_ b, right_ c C++ Ternary Node Implementation Douglas C. Schmidt void Ternary_Node::print std::ostream &stream const stream this- operation_ "" this- left_ recursive call "," this- middle_ recursive call "," this- right_ recursive call ""; Vanderbilt University 42 Vanderbilt University Vanderbilt University 5 - - 43 OO Pattern Examples C++ Ternary Node Implementation cont'd struct Tree_Node enum NUM, UNARY, BINARY, TERNARY tag_; same as before union same as before. But, add this: struct Tree_Node *l_, *m_, *r_; ternary_; c; define ternary_ c.ternary_ ; Douglas C. Schmidt OO Pattern Examples Modified class Tree Factory class Tree add 1 class constructor public: Tree const string &, const Tree &, const Tree &, const Tree & : node_ new Ternary_Node op, l, m, r Same as before . . . On the other hand, modifying the original algorithmic approach requires changing 1 the original data structures, e.g., Di erences from Algorithmic Implementation Douglas C. Schmidt Vanderbilt University 44 Vanderbilt University 45 OO Pattern Examples Di erences from Algorithmic Implementation cont'd Douglas C. Schmidt OO Pattern Examples Summary of Expression Tree Example Douglas C. Schmidt & 2 many parts of the code, e.g., void print_tree Tree_Node *root same as before case TERNARY: must be TERNARY. printf ""; print_tree root- ternary_.l_; printf "c", root- op_ 0 ; print_tree root- ternary_.m_; printf "c", root- op_ 1 ; print_tree root- ternary_.r_; printf ""; break; same as before OO version represents a more complete modeling of the application domain e.g., splits data structures into modules that correspond to objects" & relations in expression trees Use of C++ language features simpli es the design and facilitates extensibility e.g., implementation follows directly from design Use of patterns helps to motivate, justify, & generalize design choices Vanderbilt University 46 Vanderbilt University 47 OO Pattern Examples Potential Problems with OO Design Douglas C. Schmidt OO Pattern Examples Case Study: System Sort Douglas C. Schmidt Solution is very data structure rich" e.g., requires con guration management to handle many headers & .cpp les! May be somewhat less e cient than original algorithmic approach e.g., due to virtual function overhead In general, however, virtual functions may be no less ine cient than large switch statements or if else chains . . . As a rule, be careful of micro vs. macro optimizations i.e., always pro le your code! 48 Vanderbilt University Develop a general-purpose system sort It sorts lines of text from standard input and writes the result to standard output e.g., the UNIX system sort In the following, we'll examine the primary forces that shape the design of this application For each force, we'll examine patterns that resolve it Vanderbilt University 49 OO Pattern Examples External Behavior of System Sort Douglas C. Schmidt OO Pattern Examples High-level Forces Douglas C. Schmidt A line" is a sequence of characters terminated by a newline Default ordering is lexicographic by bytes in machine collating sequence e.g., ASCII The ordering is a ected globally by the following options: Ignore case -f Sort numerically -n Sort in reverse -r Begin sorting at a speci ed eld -k Begin sorting at a speci ed column -c Your program need not sort les larger than main memory 50 Solution should be both time & space e cient e.g., must use appropriate algorithms and data structures E cient I O & memory management are particularly important Our solution uses minimal dy...
View Full Document

{[ snackBarMessage ]}