Douglas C. Schmidt: Case Studies Using Patterns
Douglas C. Schmidt: Case Studies Using Patterns
Schmidt
Case Studies Using Patterns
The following slides describe several case studies using C++ & patterns
Object-Oriented Design Case Studies with
1. Expression Tree
Douglas C. Schmidt { e.g., Adapter, Factory, Bridge
Professor Department of EECS 2. System Sort
{ e.g., Facade, Adapter, Iterator, Singleton, Factory Method, Strategy,
[email protected] Vanderbilt University Bridge
www.dre.vanderbilt.edu/schmidt/ (615) 343-8197 3. Sort Verier
{ e.g., Strategy, Factory Method, Facade, Iterator, Singleton
Vanderbilt University 1
INTEGER
NODES
op_
use_
tag_
num_
unary_
binary_
LAYOUT
MEMORY
Vanderbilt University
Vanderbilt University
OO Pattern Examples
OO Pattern Examples
Expression trees
Generate code
Tree
Node
1
1|2
CLASS
RELATIONSHIPS
Perform semantic analysis
Tree
Node
Traverse & print the expression tree
Node
e.g., in-order, post-order, pre-order, level-order
Expression Tree Behavior
object
Memory Layout of Algorithmic Version
{ The evaluation step may perform various operations, e.g.,
6
Douglas C. Schmidt
4
Douglas C. Schmidt
1. Tight coupling between nodes & edges in union representation { Easy to make mistakes switching on type tags . . .
2. Complexity being in algorithms rather than the data structures Solution wastes space by making worst-case assumptions wrt structs &
{ e.g., switch statements are used to select between various types of
unions
nodes in the expression trees
{ Compare with binary search! { This is not essential, but typically occurs
3. Data structures are \passive" & functions do most processing work { Note that this problem becomes worse the bigger the size of the
explicitly largest item becomes!
class Int Node: used for implicitly converting int to Tree node
UNARY
Bridge
{ Decouple an abstraction from its implementation so that the two can
vary independently
Ternary Node e.g., printing contents of a subtree and managing memory
Node 1
2 Adapter
-a
1 has
3 Tree { Convert the interface of a class into another interface clients expect
e.g., make Tree conform C++ iostreams
tag
op
tag
PART))
PART))
PART))
left
right
left_
PART
middle
right_
Node
PART
Node
operator
middle_
(Tree
(Tree
(Tree
public:
Binary_Node (const string &op,
Node
PART))
PART))
Ternary
left
right
left_
PART
Node
PART
right_
Node
Node
operator
Binary
operator_
(TreePART
(Tree
(Tree
PART
Node
PART
operand
Node
operator
private:
operand_
operator_
(TreePART
(Tree
Unary Node
vptr
num
vptr
use_
PART
Tree
num_
Node
node_
PART
Node
Node
Tree right_;
Int_Node
};
Memory Layout for C++ Version
Memory layouts for dierent subclasses of Node
OO Pattern Examples
Vanderbilt University
Vanderbilt University 18
OO Pattern Examples Douglas C. Schmidt OO Pattern Examples Douglas C. Schmidt
C++ Int Node Implementations C++ Unary Node Implementations
#include "Int_Node.h" #include "Unary_Node.h"
Int_Node::Int_Node (int k): num_ (k) { } Unary_Node::Unary_Node (const string &op, const Tree &t1)
: operation_ (op), operand_ (t1) { }
void Int_Node::print (std::ostream &stream) const {
stream << this->num_; void Unary_Node::print (std::ostream &stream) const {
} stream << "(" << this->operation_ <<
<< this->operand_ // recursive call!
<< ")";
}
knowledge
creates
This pattern resolves the following forces:
{ Decouple initialization of the Node subclasses from their subsequent Product product = ...
return product
use
{ Makes it easier to change or add new Node subclasses later on
e.g., Ternary nodes . . .
Product
A generalization of the GoF Factory Method pattern
This pattern resolves the following forces that arise when building
Note how this pattern decouples the Tree interface for printing from the
Node subclass implementation
Int Node { i.e., the Tree interface is xed, whereas the Node implementation
Ternary
print() Binary Node varies
Node Unary print() { However, clients need not be concerned about the variation . . .
print() Node
print()
of incompatible interfaces
Forces
This pattern resolves the following force:
{ Want to integrate our existing C++ Tree class into the I/O Stream
paradigm without modifying our class or C++ I/O 1. How to transparently integrate the Tree with the C++ istd::ostream
operators
Solution
{ Use the Adapter pattern to integrate Tree with I/O Streams
return 0;
// Destructors of t1 \& t2 recursively
} // delete entire tree when leaving scope.
Do
Binary
Unary
Node
Node
Node
Int
Binary
Unary
Node
Node
Node
Int
Expression Tree Diagram 1
4
4
)
print(
)
print(
3
3
*
t2
*
t1
*
t1
5
OO Pattern Examples
OO Pattern Examples
Vanderbilt University
Vanderbilt University
-
5
-
OO Pattern Examples Douglas C. Schmidt OO Pattern Examples Douglas C. Schmidt
Adding Ternary Nodes C++ Ternary Node Implementation
#include "Ternary_Node.h"
Extending the existing program to support ternary nodes is Ternary_Node::Ternary_Node (const string &op,
straightforward const Tree &a,
{ i.e., just derive new class Ternary Node to handle ternary operators, const Tree &b,
e.g., a == b ? c : d, etc. const Tree &c)
: operation_ (op), left_ (a), middle_ (b),
#include "Node.h" right_ (c) {}
class Ternary_Node : public Node {
public: void Ternary_Node::print (std::ostream &stream) const {
Ternary_Node (const string &, const Tree &, stream << this->operation_ << "("
const Tree &, const Tree &); << this->left_ // recursive call
virtual void print (std::ostream &) const; << "," << this->middle_ // recursive call
private: << "," << this->right_ // recursive call
const string operation_; << ")";
Tree left_, middle_, right_; }; }
Vanderbilt University 42 Vanderbilt University 43
OO Pattern Examples Douglas C. Schmidt OO Pattern Examples Douglas C. Schmidt
C++ Ternary Node Implementation (cont'd) Dierences from Algorithmic Implementation
// Modified class Tree Factory On the other hand, modifying the original algorithmic approach requires
class Tree { changing (1) the original data structures, e.g.,
// add 1 class constructor
struct Tree_Node {
public:
enum {
Tree (const string &, const Tree &,
NUM, UNARY, BINARY, TERNARY
const Tree &, const Tree &)
} tag_; // same as before
: node_ (new Ternary_Node (op, l, m, r)) {}
union {
// Same as before . . .
// same as before. But, add this:
struct {
Tree_Node *l_, *m_, *r_;
} ternary_;
} c;
#define ternary_ c.ternary_
};
STRATEGIC
Sort
{ e.g., Singleton, Factory, Adapter, Iterator COMPONENTS
Line_Ptrs
Sort_AT
Implement a framework to coordinate components Adapter
ARRAY
{ Input { Sort
Eciently reads arbitrary sized input using only 1 dynamic allocation e.g., both quicksort & insertion sort
& 1 copy
1: ARRAY::TYPE t
= array[i]
"conforms to"
Adapter Adaptee
Line_Ptrs
request() 2: specific_request() specific_request()
Sort_AT_Adapter TYPE
typedef Line_Ptrs TYPE Access_Table
make_table()
operator[] make_table()
size() length()
element()
Factory Options
make_product() parse_args()
creates
creates
Compare
Product Function
Line Ptrs
Concrete Sort AT
Creator Adapter
factory_method() make_table()
Concrete
CREATES
Product return new Concrete_Product // initialize the table
size_t count = 0;
// Factory Method initializes Access_Table<>.
at.make_table (num_lines, buffer);
}
Input original;
Input potentially_sorted;
Do
OO Pattern Examples Douglas C. Schmidt
Design Patterns in Sort Verier
TYPE
Using the Strategy Pattern
Table
Hash
TYPE
TYPE
Strategy
Search
Nodups
Struct
Binary
Search
In addition, the Facade, Iterator, Singleton, & Strategy patterns are used
Vanderbilt University
check_sort
long
Vector
Range
Vanderbilt University 134
OO Pattern Examples Douglas C. Schmidt OO Pattern Examples Douglas C. Schmidt
The Factory Method Pattern Structure of the Factory Method Pattern
Intent
{ Dene an interface for creating an object, but let subclasses decide Creator
which class to instantiate factory_method() = 0
Concrete
CREATES
Product return new Concrete_Product