|
CS 635: Advanced Object-Oriented Design & Programming |
|
---|
Spring Semester, 1998
Strategy and Null Object
To Lecture Notes Index
© 1998, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 21-Apr-98
Contents of Doc 10, Strategy and Null Object
References | slide # 1 |
| |
Strategy | slide # 2 |
...Intent | slide # 2 |
...Applicability | slide # 5 |
...Consequences | slide # 6 |
...Implementation | slide # 7 |
| |
NullObject | slide # 8 |
...Applicability | slide # 9 |
...Consequences | slide # 10 |
...Implementation | slide # 11 |
...Smart Node - Ordered Linked List
Example | slide # 12 |
...... Sample Node Code | slide # 15 |
| |
Logger Revisited | slide # 18 |
References
Design Patterns: Elements of Resuable Object-Oriented Software, Gamma, Helm,
Johnson, Vlissides, Addison-Wesley, 1995, pp 315-314
"Null Object", Woolf, in Pattern Languages of Program Design 3, Edited by
Martin, Riehle, Buschmmann, Addison-Wesley, 1998, pp 5-18
Strategy
Intent
Define a family of algorithms, encapsulate each one, and
make them interchangeable
Strategy lets the algorithm vary independently from clients
that use it
Examples
Sorting
Different types of sorts have different characteristics
Shellsort
- No extra space needed
- Fast but not O(n*log(n))
- Very fast on nearly sorted data
- Does comparatively well on small lists
Quicksort
- Average case is O(n*log(n))
- Relatively poor performance on short lists
- Requires a stack of ~ log(n) in depth
MergeSort
- Worst case is O(n*log(n))
- Requires O(n) extra space
- Stable
Have a sorted list container, which one gives a sort algorithm
SortedList studentRecords = new SortedList( new ShellSort() );
studentRecords.add( "Sam" );
etc.
Pattern Matching
Finding a pattern in text is a common operation
Find the first occurrence of the word "NullObject" in this set of
notes after this line of text.
There are various algorithms one can use:
Brute Force
- Easy to implement
- Bad worst case, but good performance in practice
KMP
- Good worst case
Boyer-Moore
- Excellent worst case
- Very hard to implement
QuickSearch
- Easy to implement
- Good performance
- Good worst case
State Machines
- Very general
Could use a text object, that has a pattern search object
Applicability
Use the Strategy pattern when
you need different variants of an algorithm
an algorithm uses data that clients shouldn't know about
a class defines many behaviors, and these appear as
multiple switch statement in the classes operations
many related classes differ only in their behavior
Consequences
Families of related algorithms
Alternative to subclassing of Context
- What is the big deal? You still subclass Strategy!
Eliminates conditional statements
- Replace in Context code like:
switch ( flag ) {
case A: doA(); break;
case B: doB(); break;
case C: doC(); break;
}
- With code like:
strategy.do();
Gives a choice of implementations
Clients must be aware of different Strategies
SortedList studentRecords =
- new SortedList( new ShellSort() );
Communication overhead between Strategy and Context
Increase number of objects
Implementation
Defining the Strategy and Context interfaces
- How does data flow between them
- Context pass data to Strategy
- Strategy has point to Context, gets data from Context
Strategies as template parameters
- Can be used if Strategy can be selected at compile-time
and does not change at runtime
Making Strategy objects optional
- Give Context default behavior
- If default used no need to create Strategy object
NullObject
NullObject implements all the operations of the real object,
but these operations do nothing
Applicability
Use the Null Object pattern when:
- Some collaborator instances should do nothing
- You want clients to ignore the difference between a
collaborator that does something and one that does
nothing - so the client does not have to explicitly check for
null or some other special value
- You want to be able to reuse the do-nothing behavior so
that various clients that need this behavior will
consistently work in the same way
Use a variable containing null or some other special value
instead of the Null Object pattern when:
- Very little code actually uses the variable directly
- The code that does use the variable is well encapsulated -
at least in one class
- The code that uses the variable can easily decide how to
handle the null case and will always handle it the same
way
Consequences
Advantages
Uses polymorphic classes
Simplifies client code
Encapsulates do nothing behavior
Makes do nothing behavior reusable
Disadvantages
Forces encapsulation
- Makes it difficult to distribute or mix into the behavior of
several collaborating objects
May cause class explosion
Forces uniformity
- Different clients may have different idea of what "do
nothing" means
Is non-mutable
- NullObject objects can not transform themselves into a
RealObject
Implementation
Too Many classes
- Eliminate one class by making NullObject a subclass of
RealObject
Multiple Do-nothing meanings
- If different clients expect do nothing to mean different
things use Adapter pattern to provide different do
nothing behavior to NullObject
Transformation to RealObject
- In some cases a message to NullObject should transform
it to a real object
- Use the proxy pattern
3. Transformation to a RealObject
Smart Node - Ordered Linked List Example
Class Structure
Object Structure
Node
- Node objects are used to create a linked list. A Node
contains an integer and a pointer to the next Node in the
list. It also has add and print operations.
StartNode
- StartNode object is used as a dummy first Node in a
linked list. EndNode and StartNode are used to make
sure a list always has two elements, eliminating the need
to deal with a list with one or zero Nodes. StartNode
passes all messages it receives on to the next Node in the
list.
EndNode
- EndNode object is used as a dummy Node at the end of a
linked list. EndNode and StartNode are used to make
sure a list always has two elements, eliminating the need
to deal with a list with one or zero Nodes. EndNode does
not pass any message on to the next Node, since it is at
the end of the list.
OrderedLinkedList
- OrderedLinkedList is the interface class for linked lists.
Main operations are create, add, and +. Client program
uses this class. OrderedLinkedList uses Node, EndNode
and StartNode to maintain the linked list. Client code
does not know about Node, EndNode and StartNode.
NullObject & LinkedList
EndNode is an example of a NullObject
The add operation would be cleaner if the EndNode could
transform itself into a Node
Is StartNode a NullObject?
Sample Node Code
Node.h
class Node {
public:
int value; /*content of Node*/
Node *next; /*pointer to next Node*/
Node();
Node(int initialValue);
virtual void print();
virtual int operator<(const Node &a);
virtual void add(Node &a);
};
/*Class Comment
Requires subclasses: EndNode and StartNode
List containing a Node must start with StartNode and end with
EndNode.
Keep StartNode and EndNode in their proper locations by using
the Node operator < to compare the contents of cells. Do not
access the contents of member variable value to determine
where a Node belongs in a list.
Print, and add, are recursive type calls. Node processes the call,
then passes it on to the next Node. EndNode ends these
recursive calls.
*/
Node.cc
#include <stream.h>
#include "Node.h"
//Effects:
// Returns new Node with pointer set to null
Node::Node()
{
next = 0;
};
//Effects:
// Return new Node with contents = initialValue
Node::Node(int initialValue)
{
value = initialValue;
next = 0;
};
//Requires:
// This is a Node in an ordered (ascending) linked list
// This Node < a
//Effects:
// Inserts a in proper location in ordered linked list
void Node::add(Node &a)
{
if (*next < a )
next->add(a);
else
{a.next = next; next = &a;};
};
//Requires:
// Value has been set in this Node and a
//Effects:
// Returns true if this Node < a
int Node::operator<(const Node &a)
{
return value < a.value;
};
//Requires:
// This Node is in linked list terminated with EndNode
//Effects:
// Prints, on standard output, value of this Node and all
// cells after this
void Node::print()
{
cout << value << " " ;
next->print();
};
Logger Revisited
What patterns are used here?
visitors since 24-Feb-98