Professional Documents
Culture Documents
Lecture 9 - Design Patterns Part 1
Lecture 9 - Design Patterns Part 1
Patterns
Part 1
Tamlin Love
Today’s Topics
Design Patterns Introduction
Types of Design Pattern
Anti-Patterns
Creational Design Patterns
Factory
Prototype
Abstract Factory
Builder
Singleton
Design Pattern Pitfalls
2
Design Patterns
A design pattern is a general, reusable solution to a commonly
occurring software design problem
A design pattern is not a ready-made code package
Rather, it is a template that a developer can modify and implement
for their particular applications
3
Design Patterns
Design patterns are different from architecture styles:
Architecture styles focus on components and how they relate to
each other
Design patterns focus on low-level code, objects and classes
If someone says “X” is a design pattern, expect code, class diagrams,
etc,
If someone says “Y” is an architecture style, expect higher level
diagrams (component diagrams, activity diagrams, etc.)
The line between architecture and design is blurry
4
What do Software Developers do?
Develop software of course!
Code
Design (requirements engineering, architecture, etc.)
But a developer’s work is never done
Understand existing software
Maintain software (fix bugs)
Upgrade (add new features)
In other words, software is constantly changing
5
Why Design Patterns?
Design patterns help anticipate change
Change is needed to keep up with reality
Change may be triggered by changing business environment or by deciding
to refactor classes that are deemed potentially problematic
Change may have bad consequences when there are unrelated reasons to
change a software module/class
Unrelated reasons are usually because of unrelated responsibilities
Change in code implementing one responsibility can unintentionally lead to
faults in code for another responsibility
Design patterns can also target complex conditional logic
Design patterns provide a common language to communicate solutions with
other developers 6
Other Considerations
When is a design pattern needed/applicable?
How can we tell if a pattern is making things better or worse?
When should we avoid patterns that will make things worse?
7
Types of Design Patterns
Creational design patterns deal with object creation mechanisms
Examples: Abstract Factory, Builder, Factory, Prototype, Singleton
Structural design patterns deal with organising objects to form larger structures and
provide new functionality
Examples: Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Proxy
Behavioral design patterns deal with recognising and realising common communication
patterns between objects
Examples: Chain of Responsibility, Command, Interpreter, Iterator, Mediator, Memento,
Observer, State, Strategy, Template, Visitor
Concurrency design patterns deal with multi-threaded programs
Examples: Active Object, Double-Checked Locking, Monitor Object, Reactor, Thread-
Specific Storage
Not covered in this course 8
References
Design Patterns: Elements of Reusable Object-Oriented Software
Written in 1994, it is a very influential text in software design
Written by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides
The so-called “Gang of Four” (GoF)
Online version
Refactoring Guru – Design Patterns
9
Anti-Patterns
An anti-pattern is a design pattern that is
ineffective and counterproductive
Anti-patterns represent common pitfalls
in software design
10
Anti-Patterns
Spaghetti Code - ad hoc software structure makes it difficult
to extend and optimize code
a.k.a. Big Ball of Mud
Lava Flow – unready code is put into production and is
added to while still in an unfinished state
Golden Hammer – obsessively applying a familiar tool to
every software problem
“If all you have is a hammer, everything looks like a nail”
Boat Anchor – code that doesn’t do anything is left in the
codebase “just in case”
God Class – one class taking on too many responsibilities
Poltergeist Class - useless classes with no real
responsibility of their own, often used to just invoke methods
in another class or add an unneeded layer of abstraction.
11
Creational Patterns
Creational design patterns deal with object creation mechanisms
With typical object creation (e.g. new Object):
Client must know which class is being created (no polymorphism)
Client must have complete control over the object creation (tight coupling)
With creational design patterns:
Object creation can be abstracted
Client may not need to know which class to create (polymorphism)
Client may not need to know how to create an object (single responsibility)
New classes can be added without changing client (open-closed)
Shifts emphasis away from pure inheritance to composition and interfaces
(can facilitate dependency inversion)
12
Factory
The factory pattern, also known as the virtual constructor pattern, uses
methods (called factory methods) to create create objects without having to
specify which class is being instantiated
A factory method is called instead of a constructor
Moves the responsibility of creating an object from the client to a factory class
13
Factory
Product – defines the interface of objects created by the factory
ConcreteProduct – implements the Product interface
Factory – declares a factory method that returns a Product. May have other methods that
use the factory method
ConcreteFactory – overrides the factory method to return a ConcreteProduct
14
Factory
Example: cross-platform UI elements
15
Factory
Use factory when:
a class can’t anticipate the class of objects it must create
a class wants its subclasses to specify the objects it creates
you want to localise knowledge about object creation
Pros:
Modular expandability – can create new concrete factories and products
without breaking client functionality (open-closed principle)
Delegates object creation responsibilities to a separate class (single
responsibility principle)
Straightforward to test
Cons:
Requires more classes than just using a straightforward constructor call 16
Prototype
The prototype pattern creates instances of an object by cloning a prototypical instance
Like factory, prototype abstracts the creation of objects
Factory and prototype often used together
Cloning existing objects is often computationally cheaper than creating new ones
Cloning an object copies its encapsulated attributes as well, which may not be known
by the client
17
Prototype
Prototype – defines the interface of cloned objects
ConcretePrototype – implements the Prototype class
Client – creates one instance of the ConcretePrototype, then clones it to make
any more
18
Prototype
Example: musical notation software
19
Prototype
Use prototype when:
a system should be independent of how its products are created, composed,
and represented
a class to be instantiated is selected at run-time (e.g. dynamic loading)
you want to avoid building a class hierarchy of factories that parallels the class
hierarchy of products
instances of a class can have one of only a few different combinations of state.
It may be more convenient to install a corresponding number of prototypes
and clone them rather than instantiating the class manually, each time with the
appropriate state
20
Prototype
Pros:
You can clone objects without coupling to their concrete classes
You can get rid of repeated initialization code in favor of cloning pre-built
prototypes
You can produce complex objects more conveniently
You get an alternative to inheritance when dealing with configuration presets
for complex objects
Cons:
Cloning complex objects that have circular references might be very tricky
21
Combo: Prototype Factory
22
Abstract Factory
The abstract factory
pattern, also known as the
kit pattern, provides an
interface for creating
families of related or
dependent objects without
specifying their concrete
classes
Note: factories can be
implemented using factory
methods or prototypes (i.e.
cloning)
23
Abstract Factory
AbstractProduct – interface for
products
ConcreteProduct – implements
AbstractProduct
AbstractFactory – declares an
interface for factories that create
AbstractProducts
ConcreteFactory – implements
AbstractFactory, creates
ConcreteProducts
Client – uses interfaces
provided by AbstractFactory and
AbstractProduct
24
Abstract Factory
Example: a UI toolkit for
different operating
systems
25
Abstract Factory
Use abstract factory when:
a system should be independent of how its products are created, composed,
and represented
a system should be configured with one of multiple families of products
a family of related product objects is designed to be used together, and you
need to enforce this constraint
you want to provide a class library of products, and you want to reveal just
their interfaces, not their implementations
26
Abstract Factory
Pros:
You can be sure that the products you’re getting from a factory are compatible with each
other
You avoid tight coupling between concrete products and client code
You can extract the product creation code into one place, making the code easier to
support
Single Responsibility Principle
You can introduce new variants of products without breaking existing client code
Open-Closed Principle
Cons:
The code may become more complicated than it should be, since a lot of new interfaces
and classes are introduced along with the pattern
27
Builder
The builder pattern separates the
construction of a complex object from its
representation
28
Builder
Motivation: Consider building a house – houses can have multiple configurations
We could represent these configurations using subclasses
Number of subclasses spiral out of control
29
Builder
Motivation:
We could represent these configurations as attributes passed to constructor
Object creation becomes very very messy
30
Builder
Motivation:
We instead break up object construction into steps and delegate the
responsibility of executing these steps to a builder class
31
Builder
Product – the complex object to be built
Builder – the interface for building
Products
ConcreteBuilder – implements Builder to
construct parts of Product
Director – optional class that coordinates
the Builder
32
Builder
Building sequence
33
Builder
Example: building cars and car manuals
34
Builder
Use builder when:
the algorithm for creating a complex object should be independent of the parts
that make up the object and how they're assembled
the construction process must allow different representations for the object
that's constructed
e.g. stone house vs wooden house
35
Builder
Pros:
You can construct objects step-by-step, defer construction steps or run steps
recursively
You can reuse the same construction code when building various
representations of products
You can isolate complex construction code from the business logic of the
product
Single Responsibility Principle
Cons:
The overall complexity of the code increases since the pattern requires
creating multiple new classes
36
Singleton
The singleton pattern restricts the instantiation of a class to a single instance
It’s often useful to have only one instance of a class. Singletons let us ensure
that a class isn’t needlessly instantiated more than once.
Often considered an anti-pattern
37
Singleton
Implementation:
Default constructor is made private
Instead, use a static creation method that calls the default constructor the first
time and returns the instance on every subsequent call
38
Singleton
Example: file logger
39
Singleton
Singletons vs Global Variables
Both singletons and global variables are globally accessible
However, singletons can encapsulate and hide information that global
variables can’t
Global variables can clutter a namespace with unnecessary variables
Singletons allow for lazy allocation (only allocate memory when needed),
whereas global variables always consume resources
Singletons can be subclassed
40
Singleton
Use singleton when:
there must be exactly one instance of a class, and it must be accessible to
clients from a well-known access point
41
Singleton
Pros:
You can be sure that a class has only a single instance
You gain a global access point to that instance
The singleton object is initialized only when it’s requested for the first time
Cons:
The Singleton pattern can mask bad design, for instance, when the components of the
program know too much about each other
In general, globally accessible components (global variables, singletons, etc.) can result in
tighter coupling
Hard to execute correctly in multi-threaded environments
Hard to create mock singletons when testing
Isn’t future proof – what if we decide we need more than one?
Violates single responsibility principle – singleton does whatever it’s supposed to do, but also
ensures there is only one of it 42
Other Creational Patterns
Not in the original GoF list:
Dependency Injection – object receives objects which it depends on
Lazy Initialisation – object creation is delayed until the object is actually
needed in order to reduce initial load
Multition – generalises the singleton to multiple instances
Object Pool – rather than creating and destroying objects, recycle them from
a pool
43
Design Pattern Pitfalls
Don’t design for patterns!
Trade-off between getting a product out quickly and optimising that product
Optimisation is secondary
Initial designs should be refactored to patterns
e.g. Designs often start out using factories (as they are simple to use and
easily customisable) and evolve towards abstract factories, prototypes or
builders as designs are refined and optimised
Uncritical use of design patterns can turn them into anti-patterns
The need for some design patterns can be eliminated through language features
Different languages and paradigms will change how you approach design
patterns
44