Design Patterns
What Are Object-Oriented Design Patterns?
Definition A pattern of fixed class structure (think UML class sub-diagram) and messaging (sequence diagram) that repeatedly pops up as a very useful programming idiom.
- In any engineering/building/modeling discipline there are important clever patterns of design that repeatedly arise and are good to know.
- Object-Oriented design patterns is a catalog of such patterns for O-O languages
- The source: Gamma et al. Design Patterns book, circa 1995. The authors are known as the "Gang of Four".
- These lectures largely follow the Head First Design Patterns (HFDPs) textbook which covers the Gang of Four patterns from a more tutorial angle.
- Another good way to view this topic is as a lesson in advanced O-O programming
The Gang of Four Patterns
We will cover the patterns in the order they are presented in the HFDPs book.Observer
See HFDPs Chapter 2.Go4 description: Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
- The key advantage of observer is it decouples subjects and observers, they are only loosely acquainted.
- Subject can read/write its fields; Observer is a part that only needs to read the subject fields so can be decoupled into a separate class.
- Java Observer class: observers are built in to Java
- Java AWT Example: AWT
Event
Listeners are a form of Observer- the listeners are to observers
- adding a listener is adding an observer
- the message sent to the observer is specific to the event
type - not generic like Java class
Observer
- "publish/subscribe" ("pub/sub") is another common name for this pattern. The publisher is the object and the observers are its subscribers.
Decorator
See HFDPs Chapter 3
Go4 description: Attach additional responsibilities to an object
dynamically. Decorators provide a flexible alternative to
subclassing for extending functionality.
Diagram
- Java IO Example - Java IO makes excellent use of decorators
- Here is a code example to make clear how the decorator "decorates"
- Swing Example: The Swing
JScrollPaneis aJComponentwhich holds aComponentthat it allows scrolling on. (Actually, it holds aJViewportwhich holds theComponent, so its slightly more complicated.) - Decorators one of many patterns incorporating significant delegation (forwarding possibly with modification).
Design Principle: The Open-Closed Principle
This principle is illustrated well by the decorator pattern; we covered it in the design lectures but will revisit it now.- Decorator allows functionality to be added which are extensions which allowed the original codebase to not change the original code
- I.e. the original code is "open to extension, closed to modification" -- OCP!
Factories
See HFDPs Chapter 4.
- Factories are methods creating objects rather than directly invoking
new. - They allow code that was low-level and dependent on a specific
class (
newrequires an explicit concrete class to be named) to instead invoke a factory to create one of many possible objects. - Another viewpoint: advantage of using interfaces or superclasses
as abstractions breaks down when you
new, so
... Factories to the rescue: they allow factory-calling code to create objects by invoking them instead of grubbing around withnew.
Window w = aWindowFactory.makeWindow()
can return a saySimpleWindowor aDecoratedWindow, both of which areWindows, and the class with the above code need not be concerned with which it got back.
Factory Method
A factory method is a generalization of a simple factory:- There is a superclass or interface which has the factory or method declared
- Subclasses or implementers specialize this factory to create the kinds of objects they need
Go4 description: Define an interface for creating an object, but let subclasses decide
which class to instantiate. Factory Method lets a class defer
instantiation to subclasses.
Diagram
- Pizza example in HFDPs
- Example in Swing:
createDefaultModel()inJtextFieldis a factory method to return a default model for your input field; you can override this in your subclassMyJTextFieldofJTextFieldto create your own model for the textfield, which e.g. allows integer inputs only. (This example is a slight variation on the pattern in that that the FactoryMethod is not abstract in the superclass; instead, it has a default behavior which can be overridden).
Design Principle: The Dependency Inversion Principle
- We covered this earlier but now we can more clearly see what it means
- The initial pizza-making code without a factory required the top-level
PizzaStoreclass to itself choose the kind of pizza: see picture from book. - Arrows in the above (read as "dependent-on") show high-level
code directly dependent on details of low-level code (it needs
their names to create them via
new) - This is backwards, the high-level code should not depend on low-level; instead, low-level should depend on high level.
- This picture shows how the depenencies got inverted whan a factory method is used
- The dependencies were inverted - D-I-P!
Abstract Factory
Go4 description: Provide an interface for creating families of related or dependent objects without specifying their concrete classes.Diagram
- Abstract Factories for Pizzas
- The key difference here compared to Factory Method is the FAMILY of related classes getting created.
- Another simple example:
Childhas subclassesBoyandGirl; you have various supplies such asToothbrush,Sheet, etc you need to make which are very similar, but theBoyToothbrushis the car toothbrush and theGirlToothbrushis the Hello Kitty one. - Example: For a distributed game, there can be a Player (A) which can be LocalPlayer (A1) or a DistributedPlayer (A2), and a Board (B) which can be a LocalBoard (B1) or DistributedBoard (B2). The abstract factory can polymorphically make either a local or distributed player. It is polymorphic because the holder of the factory need not know whehter its local or distributed; the factory itself holds that information.
Singleton
HFDPs Chapter 5. Go4 description: Ensure a class has only one instance and provide a global point of access to it.Diagram
- For a class with only one member, something quite common in practice.
- Code it so that multiple instances can't be created.
- Have a class method to get the sole instance.
Answer:
- Static methods are directly globally visible, violating encapsulation boundaries.
- You can't pass classes as arguments; also no object polymorphism with classes
- This will not be extensible if for some reason two are needed.
Command
HFDPs Chapter 6
Go4 description: Encapsulate a request on an object, thereby letting one parameterise
clients with different requests, queue or log requests, and
support undoable operations.
Diagram
- In this diagram,
Invokerwants to perform a command,ConcreteCommandis the object containing the actual command details (abstractly shown here to be a message toReceiver), andCommandis an abstract superclass so we can generically support a multitude of concrete commands. IgnoreClient. - Since these commands are now objects we can put them on a log
queue, use that queue to implement an
undo()action, even make a decorator for commands, etc etc.
Adapter
HFDPs Chapter 7
Go4 description: Convert the interface of a class into another interface clients
expect. Adapter lets classes work together that couldn't otherwise
because of incompatible interfaces.
Diagram
- First, the case when an adapter isn't needed is when there is a common interface and the object you want to use implements this interface.
- Second, there is the case when the interface is incorrect or incomplete for uses, but you can easily change it and that will solve the problem -- do it!
- The third case is the bad thing: there is an interface,
but it isn't quite what you need and either you can't change it
or if you changed it to the way you wanted it would mess up
some other code.
- It may have method names slightly different;
- It may be missing one of the methods and so some default value must be popped in for that method
- Some translation of the data may be needed, e.g. your interface expects rectangular coordinates for a point and the object you want to use expects polar coordinates.
- You may want to add some extra functionality in the
Decoratorspirit, e.g. log requests.
- Then, the solution in the above case is to create a new intermediate object, the adapter, which serves to adapt the interface for that object.
- The book has a good example of how the old Java
Enumerationclass can be adapted to work like the newIteratorclass. - (Note the Swing MouseAdapter etc classes are somewhat different than this notion of adapter, they are not a forwarding intermediary -- the use of "Adapter" there is thus confusing)
Façade
HFDPs Chapter 7Go4 description: 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.
- A facade turns a bunch of wild objects into a component, by putting the interface of interaction with those objects on one object, the facade.
- Facade objects don't do the work, they just delegate (forward messages) to other objects.
- Facades can also do adapting, such as supplying some of the arguments to lower-level methods, invoking multiple methods, etc.
- Example: Home theater system example from book
Design Principle: The Principle of Least Knowledge
Talk only to your immediate friendsWe covered this earlier, but there is one more point to make:
- Facade is a great pattern primarily because of how effectively it implements this principle.
- The "users" of the large collection of objects under the facade only need to talk to the facade object (their immediate friend) and not all of the other objects.
Template Method
HFDPs Chapter 8
Go4 description: Define the skeleton of an algorithm in an operation, deferring some
steps to subclasses. Template Method lets subclasses redefine
certain steps of an algorithm without changing the algorithm's
structure.
Diagram
- The template is an algorithm with "holes" in the superclass
- the subclasses implement the "holes"
- Some steps in the algorithm may be common to all implementations so that code can be in the superclass
- Code Outline which shows a simple templated method
- Example Code for coffee or tea brewing; diagram of this example
- Swing use of a
template method in
JFrame: theupdate()method ofJFrame(not shown) callspaint().
Design Principle: the Hollywood Principle
Don't call us, we'll call youTranslation:
- Context: a high-level component is talking to a low-level component.
- It is the high-level component that is in control of the process
- High-level component has a (general) interface for invoking low-level component
- Low-level component services the high-level component via the calls
- The superclass with the template in it is the high-level component
- The subclasses are the low-level components
- The super is in control and calls the subs
Iterator
HFDPs Chapter 9
Go4 description: Provide a way to access the elements of an aggregate object
sequentially without exposing its underlying representation.
Diagram
- The Java Collections Framework includes an Iterator
interface w/methods
next(), hasNext(), remove()(remove removes the current method from the underlying collection). - Iterators need to hold the state of progress of one iteration through the object, so you make a new one of these guys for each iteration through the collection.
- The take-home message here is not only can you use iterators on
Java collections, implement
Iteratoron your own classes which you may need to iterate through.
Composite
HFDPs Chapter 9
Go4 description: Compose objects into tree structures to represent part-whole
hierarchies. Composite lets clients treat individual objects
and compositions of objects uniformly.
Diagram
- This is a very basic and critical pattern we already ran into several times.
- If you needed a recursive union type in C, use the composite pattern in an OO language.
- This is another way switch statements get done away with: a switch on such a union amounts to dynamic class lookup which is bad; instead, ask the objects to do the task their way.
- Example:
Component/Containerof Swing.- Swing implements a variation on Composite:
JComponentis a subclass ofContainer, and soJComponentand all its subclasses (i.e., all Swing widgets) are themselves containers. - Also,
paintin aJComponentcontainer first paints the component (paintComponent) and then all of its children, if any (paintChildren()).
- Swing implements a variation on Composite:
JButton is a Container: we add a tree component to a
JButton "composite/container":
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
public class TreeOnButton {
public static void main(String[] args) {
JButton button = new JButton();
button.setLayout(new BorderLayout());
final JLabel buttonText = new JLabel("Press me",
JLabel.CENTER);
button.add(buttonText, BorderLayout.NORTH);
JTree tree = new JTree();
tree.addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) {
buttonText.setText("Press for " +
e.getPath().getLastPathComponent());
}
});
button.add(tree, BorderLayout.CENTER);
JFrame f = new JFrame("Tree on Button");
f.getContentPane().setLayout(new FlowLayout());
f.getContentPane().add(button);
f.setSize(500,500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.show();
}
}
Run it and watch some strange stuff ("don't do this at home").
State
HFDPs Chapter 10
Go4 description: Allow an object to alter its behaviour when its internal state
changes. The object will appear to change its class.
Diagram
- The actions of inserting a coin, turning crank, etc vary depending on the state of the machine (coin previously inserted etc)
- Bad way to do it -- a bunch of
switchorif-then-elsestatements. - Better way to do it: With the State Pattern! Here is the main class code and here are some state classes.
Price was introduced which is the
State above, and it had subclasses
RegularPrice, etc; Movie is the
Context above, holding the Price state).
Strategy
(This pattern was touched on in HFDPs Chapter 1)Go4 description: Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
- This is nearly identical to State, it supports dynamic changing of some aspects of a class--in this case an algorithm.
- The class diagram and sequence diagram are identical as well.
- In fact it is arguably the same pattern: the algorithm is in fact varying because of some underlying state change.
Proxy
HFDPs Chapter 11
Go4 description: Provide a surrogate or placeholder for another object to control
access to it.
Diagram
Proxies are one of the most useful advanced patterns, with many purposes
- Virtual Proxy: maybe actual object hasn't been created or loaded yet (lazy creation),
- Java RMI uses remote proxies for remote objects, and Hibernate uses proxies for database-stored objects.
- Proxies can be used for access control: e.g.
ReadOnlyGoobercould be a proxy class for aGooberwhich does not forward setter messages toGoober, but forwards all others. - Java also has a
Proxyclass- It is a variant on the proxy pattern: there may not even be a real subject!
- The handling of messages can also be dynamically decided - it is a dynamic proxy.
-
Here is a code example of how
the Java
Proxyclass is used.
- Proxy is the special case of adaptation/delegation where nearly all methods of one object delegate to the same method in another object.
More Gang of Four Patterns
The patterns from here on down are not as central as the ones above and for most of them we will not cover them in as much depth. They are summarized in Chaper 14 of the HFDPs book.Bridge
HFDPs p.612
Go4 description: Decouple an abstraction from its implementation so that the two can
vary independently.
Go4 Diagram:

Bridge is an apt name, because it forms a bridge between two inheritance heirarchies.
Bridge emerges as a result of a refactoring which introduces delegation:
- Suppose you have a complex inheritance tree (example:
Windowwith subclassesIconWindow,Dialog, etc) - Suppose there are also different modalities of implementation of the whole tree, for example PC, UNIX, and Mac-specialized implementations are needed.
- Refactor this mess into two trees, an
abstraction hierarchy which is the original
Window/IconWindow/Dialogtree with the PC/Mac/UNIX implementation bits removed, and an implementation tree which has an abstractImplementationclass and each concreteImplementationMac,ImplementationPC,ImplementationUNIXas subclasses. - The abstract tree then delegates to its implementation object for the low-level code.
Builder
HFDPs p.614
Go4 description: Separate the construction of a complex object from its representation
so that the same construction process can create different
representations.
Go4 Diagram:
- the
Directorneeds to create many different kinds of parts to make the full product. In the stupid method, the director has a whole pile of different classes he has tonew. - In the smart method above, he has a uniform pile (an
Arraysay) ofBuilder's, and by invokingBuildPart()on each one in a loop, he gets all his parts made with minimal code fuss. - the
ConcreteBuilderis a particular concreteBuilder, a factory class, designed to createProduct's.
Chain of Responsibility
HFDPs p.616
Go4 description: Avoid coupling the sender of a request to its receiver by giving
more than one object a chance to handle a request. Chain the
receiving objects and pass the request along the chain until an
object handles it.
Go4 Diagram:
- This pattern shares some structural similarities with Java exceptions: either they are handled or passed on. But with exceptions they are implicitly passed on if they are not handled; here the passing on is explicit
- This pattern is useful for hierarchical structures where a request can be handled at multiple layers.
- Example: GUI event handling can be done hierarchically. If a contained view doesn't want to handle an event it can delegate it to its container, etc up the chain to the window. Java doesn't use this event model however.
Flyweight
HFDPs p.618
Go4 description: Use sharing to support large numbers of fine-grained objects
efficiently.
Go4 Diagram:
- This is a more specialized pattern, not used as often as the others.
- Example: Suppose a card game required 50 decks of cards. Only one set of actual cards need be created and shared
Interpreter
HFDPs p. 620
Go4 description: Given a language, define a representation for its grammar along
with an interpreter that uses the representation to interpret
sentences in the language.
Go4 Diagram:
- This is a very specific pattern to represent language syntax.
- It is a variation on
Composite. In general it is also likeCompositeshowing howuniontypes are encoded via this recursive diagram structure.
Mediator
HFDPs p. 622 Put someone in charge (a mediator) of an interaction between two classes.
Go4 description: 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 it lets one vary
their interaction independently.
Go4 Diagram:
Memento
HFDPs p. 624
Go4 description: Without violating encapsulation, capture and externalise an object's
internal state so that the object can be restored to this
state later.
Go4 Diagram:
- This pattern can be one useful way to interact with a database in an object-oriented fashion: keep mementos around of all objects
Prototype
HFDPs p. 626
Go4 description: Specify the kinds of objects to create using a prototypic instance
and create new objects by copying this prototype.
Go4 Diagram:
- When you want new objects, copy from a prototype instead of creating directly from a class.
- Useful when its a significant effort to create object structure from scratch.
-
Example:
To create a new
Deckof 52 playing cards, cards could be copied from a static variable inDeckwhich was originally initialized when the class was loaded to hold a "fresh"DeckofCardobjects rather than making cards all over again.
Visitor
HFDPs p. 628
Go4 description:
Represent an operation to be performed on the elements of an object
structure. Visitor allows one to define a new operation without
changing the classes of the elements on which it operates.
Go4 Diagram:
- Suppose you have an
Elementobject in a variable and need to perform aswitchon what concrete subclass ofElementwe in fact have. - Note that this is an incredibly common C programming
pattern on
uniontypes -- you are casing on which branch of the union you are in (the C analogy of inheritence is union). - The problem is this notion does not fit well with O-O, the union is treated as passive in this switch; you are also casing at run-time on what class an object is, a brittle programming pattern.
- Alternative 1: add a method to each class in the union to do the walkthrough
- Big Advantage: we kept things highly O-O!
- Big Disadvantage: this is shotgun surgery -- each time we want to do such a switch we have to add a method to all the classes in the tree. Code gets all spread out.
- Alternative 2: Visitor
- Add an intermediary class, the visitor, which holds all the cases
- The classes in the original inheritance hierarchy gets a new method
Acceptto help "walk" the visitor through the union - ... this is a compromise, we are not completely violating O-O and we avoid shotgun surgery when adding an operation over the tree, but it adds complexity to the design.
- Note that if we add a new concrete element type we on the other hand have to do surgery on all visitors. But, we have localized the surgery to just the visitors.
- This pattern is another pattern that is useful to get rid of switch statements.
- Abstract superclass
Visitoris the superclass of all visitors ConcreteVisitor1is a concrete visitor (e.g. we make a classGetHealthRatingforgetHealthRating()in the menu example); we make newConcreteVisitorXfor each different switch we wanted to do over the union.ConcreteVisitor1has a methodvisitConcreteElementAetc for each kind of node A/B/.. in the original union structure - this is where the code in the original switch for the case it isA/B.. goes.anElement.accept(aVisitor)starts the visiting process- This method in each inheritence class
ConcreteElementAetc in turn calls the correct "case" to be performed on it, e.g.ConcreteElementAcallsvisitConcreteElementA(this)which will run the correct case of the switch..