Design Patterns: Recommended Reading and Lecture Sources
Design Patterns: Recommended Reading and Lecture Sources
CS 580
By Robert Stehwien
Recommended Reading
and Lecture Sources
• “Design Patterns: Elements of Reusable Object-
Oriented Software” by Erich Gamma, Richard
Helm, Ralph Johnson, John Vlissides
• “Refactoring to Patterns” by Joshua Kerievsky
– http://www.industriallogic.com
• “Head First Design Patterns” by Eric Freeman &
Elisabeth Freeman with Kathy Sierra & Bert
Bates
• “Object-Oriented Design Heuristics” by Arthur J.
Riel
1
What’s a pattern?
• A pattern is a named abstraction from a concrete form
that represents a recurring solution to a particular
problem.
• Patterns = problem/solution pairs in context
• Patterns facilitate reuse of successful software
architectures and design
• Not code reuse
– Instead, solution/strategy reuse
– Sometimes, interface reuse
• Best practices
• “Patterns are discovered, not invented” - Richard Helm
2
Categories of Patterns
• Design patterns vary in granularity and level
of abstraction.
• By categorizing patterns, it becomes easier
to recognize and learn them
• Categorized by purpose or scope
• Purpose reflects what the pattern does
• Scope specifies if the pattern applies to
classes or objects
Purpose
• Reflects what the pattern does
• Creational – facilitate object creation
• Structural -- deal with the composition of
classes or objects
• Behavioral -- deal with the way objects
interact and distribute responsibility
3
Scope
4
How do Design Patterns Solve
Design Problems?
• The meaning of OO is well-known
• The hard part is decomposing the
system into objects to exploit:
– encapsulation
– flexibility, extensibility
– ease of modification
– performance
– evolution
– reusability
Finding Objects
5
Inheritance
• Inheritance is a mechanism for reuse
• You can define a new kind of object in
terms of the old one
• You get new implementations almost for
free, inheriting most of what you need from
an existing class
• This is only half the story!
Program to an interface,
not an implementation
• Inheritance permits defining a family of
objects with identical interfaces
• Polymorphism depends on this!
• All derived classes share the base class
interface
• Subclasses add or override operations,
rather than hiding operations
• All subclasses then respond to requests in
the interface of the abstract class
6
Inheritance properly used
• Clients are unaware of types of objects: heuristic
5.12 - “explicit case analysis on the type of an
object is usually an error. The designer should use
polymorphism”. Riel
• Clients only know about the abstract classes
defining the interface. heuristic 5.7: “All base
classes should be abstract”. Riel
• This reduces implementation dependencies
• Program to an interface, not an implementation
• Creational patterns help ensure this rule!
7
Advantage of Inheritance for
Reuse
• Defined statically
• Supported directly by the language:
straightforward to use
• Easier to modify implementation being
reused
Disadvantage of Inheritance
• Can’t change inherited implementation at
run-time
• Parent classes often define part of their
subclasses physical representation
• Because inheritance exposes the parent
implementation it’s said to “break
encapsulation” (GOF p.19, Sny86)
• Change in parent => Change in subclass
• If inherited attribute is inappropriate?
8
Duck Example
Extending Duck
• Static ducks not enough to compete
• Ducks need to fly()
• Inheritance seems like a good way to go
9
Flying Duck 1
10
Decoy and Rubber Ducks
11
Object Composition:
Black Box Reuse
• Objects are accessed solely through their
interfaces: no break of encapsulation
• Any object can be replaced by another at
runtime: as long as they are the same type
• Favor object composition over class
inheritance. GOF p. 20
• But inheritance & composition work
together!
Delegation
12
Delegation: Reuse
• In delegation, 2 objects handle a request
• Analogous to subclass deferring request to
parent
• In delegation, the receiver passes itself to
the delegate to let the delegated operation
refer to the receiver!
Rectangle
Window
rectangle area()
area() width
height
return rectangle->area()
return width*height
13
Advantages of Delegation
• Can change behaviors at run-time
• Window can become circular at run-time
by replacing Rectangle with Circle,
(assuming Rectangle & Circle are same type!)
• There are run-time costs.
• Delegation in patterns: State, Strategy,
Visitor, Mediator, Bridge
Redesigned Duck
14
Encapsulated Quack Behavior
15
Strategy Pattern
• Surprise! That is the strategy pattern
• Strategy Pattern:
– Defines a family of algorithms, encapsulates
each one, and makes them interchangeable.
– Strategy lets the algorithm vary independently
from clients that use it
16
Patterns Make Design Resistant to Re-Design
Robustness to Change
• Extending functionality by subclassing:
Command, Bridge, Composite, Decorator,
Observer, Strategy
• Inability to alter classes conveniently: Visitor,
Adapter, Decorator
Design Confidence
• Design Inexperience: “Is my design ok?”
• Patterns engender confidence
– used twice & blame the GOF
– still room for creativity
17
Design Coverage
• Large portion of design can be covered by
patterns
• Seductively simple to implement
– most explained in a few pages
– add no “extra-value” to end-user
• You still have to write functionality:
patterns don’t solve the problem
Design Understanding
• “Most” people know the patterns
If you’re looking at someone’s design & you
identify a pattern, you immediately understand
much of the design
• Common design vocabulary
– “Let’s use a Builder here”
• Design language beyond language syntax
– problem oriented language
– program in rather than into the language
18
Common Problems
• Getting the “right” pattern
• Taming over-enthusiasm
– you “win” if you use the most patterns
– everything solved by the last pattern you
learned
• Over-Engineering
– More sophisticated or flexible than necessary
Criticisms
• Targets wrong problem
– Missing language features
• Lacks formal foundations
• Does not provide reuse (like components)
• Leads to inefficient solutions
• Does not differ significantly from other
abstractions
– Model-View-Controller predates GoF patterns
19
How to select a pattern
• Know a basic catalog
• Scan intent section
• Study patterns of like purpose
• Consider a cause of redesign
20
Creational Patterns
• Abstract Factory: Provide an interface for creating families of
related or dependent objects without specifying their concrete class.
• Builder: Separate the construction of a complex object from it
representation so that the same construction process can create
different representations.
• Factory Method: Define an interface for creating an object, but let
subclasses decide which class to instantiate. Factory Method lets a
class defer instantiation to subclasses.
• Prototype: Specify the kinds of objects to create using a protypical
instance, and create new objects by copying this prototype.
• Singleton: Ensure a class only has one instance, and provide a
global point of access to it.
21
Structural Patterns (2)
• Decorator: Attach additional responsibilities to
an object dynamically. Decorators provide a
flexible alternative to subclassing for extending
functionality.
• Façade: Provide a unified interface to a set of
interfaces in a subsystem. Façade defines a
higher-level interface that makes the subsystem
easier to use.
• Flyweight: Use sharing to support large
numbers of fine-grained objects efficiently.
• Proxy: Provide a surrogate or placeholder for
another object to control access to it.
22
Behavioral Patterns (2)
• Iterator: Provide a way to access the elements of an
aggregate object sequentially without exposing its
underlying representation.
• Mediator: Define an object that encapsulates how a set
of objects interact. Mediator promotes loose coupling by
keeping objects from referring to each other explicitly,
and lets you vary their interaction independently.
• Memento: Without violating encapsulation, capture and
externalize an object’s internal state so that the object
can be restored to this state later.
• Observer: Define a one-to-many dependency between
objects so that when one object changes state, all its
dependents are notified and updated automatically.
23
Study Guide (1)
• Courtesy of the author of "Refactoring to Patterns"
– http://www.industriallogic.com/papers/learning.html
24
Study Guide (3)
• (S) Bridge: Finally, the reader learns how the Bridge pattern differs
from both the Adapter and Proxy patterns.
• (B) Mediator: Now the reader learns the Mediator pattern, in
preparation for understanding Observer and the Model-View-
Controller design.
• (B) Observer: Discover how the Mediator is used by the Observer to
implement the classic Model-View-Controller design.
• (B) Chain of Responsibility: After exploring how messages are
passed using the Observer and Mediator patterns, the reader now
may contrast how messages are handled by the Chain of
Responsibility pattern.
• (B) Memento: The reader now moves on to Memento. This pattern
leads directly into a discussion of undo and redo, which is related to
the next pattern, Command.
• (B) Command: The Command pattern is used in a number of ways,
one of which relates to the previous pattern, Mediator.
25
Factory Method:
Motivating example
• Consider class Number with derived
classes BigInt and Complex, with most
derived class operations as virtual in
Number.
• Users can use a pointer or reference to
Number, bind the pointer to any of the
member of the hierarchy and interact
without knowing what “it” is!
Factory Method:
Number Hierarchy
Number
Users of this hierarchy
can interact with any
“number”, treating them
all equally.
26
Factory Method:
virtual constructors
• We may want the instantiation to be
accomplished from w/in the hierarchy
• perhaps when number becomes too large,
Number switches to a BigInt
• perhaps when the user takes the sqrt of a
negative number, “it” switches to a
Complex
27
Where to build/switch the
“number”?
Number let the Number constructor
build the object:
Number::Number() {
if (some condition)
this = new BigNumber;
Complex BigInt }
Factory Method:
Where to build/switch the “number”?
soln: use Number
class Number {
public:
Number(istream &);
Number* operator*(const Number& n) {
return rep->operator*(n);
}
private:
Number * rep;
enum NumType {COMPLEX, FLOAT, BIGINT};
NumType numParse(const string &);
};
28
Where to build/switch the
“number”?
Number::Number(istream & s) { The constructor
string buf; is the factory &
getline(cin, buf); it’s acting like a
switch (NumParse(buf) ) { “virtual” function
case COMPLEX:
rep = new Complex(buf); break;
case FLOAT:
rep = new Float(buf); break; Envelope/Letter
case BIGINT:
rep = new BigInt(buf); break;
}
} Note that the constructor
method is the factory!
Factory Method:
Defined
• Define an interface for creating an object, but let subclasses decide which
class to instantiate. Factory Method lets a class defer instantiation to
subclasses.
– A class used to create other objects
29
Factory Method:
Sequence Diagram
Decorator:
Defined
• Attach additional responsibilities to an object dynamically.
Decorators provide a flexible alternative to subclassing for extending
functionality.
– Objects that wrap around other objects to add useful features
– Any calls that the decorator gets, it relays to the object that it contains, and adds
its own functionality along the way, either before or after the call.
30
Decorator Pattern: UML
Decorator pattern
• decorator: an object that modifies behavior of, or adds
features to, another object
– decorator must maintain the common interface of the object it
wraps up
• used so that we can add features to an existing simple
object without needing to disrupt the interface that client
code expects when using the simple object
• examples in Java:
– multilayered input streams adding useful I/O methods
– adding designs, scroll bars and borders to GUI controls
31
Decorator example: I/O
• normal InputStream class has only public int
read() method to read one letter at a time
• decorators such as BufferedReader or Scanner
add additional functionality to read the stream
more easily
32