Title: DEPARTMENT OF COMPUTER SCIENCE AND SOFTWARE ENGINEERING
1DEPARTMENT OF COMPUTER SCIENCE AND SOFTWARE
ENGINEERING CONCORDIA UNIVERSITY
C Design Patterns
Joey Paquet, Emil Vassev. 2007, 2011,
2013
2Outline
- Introduction to Design Patterns
- Patterns Elements
- Types of Design Patterns
- C Design Patterns
- Creational Patterns
- Structural Patterns
- Behavioral Patterns
3Design Patterns
What is a Design Pattern?
- Each pattern describes a problem which occurs
over and over again in our environment, and then
describes the core of the solution to that
problem, in such a way that you can use this
solution a million times over, without ever doing
it the same way twice. 1 - Christopher Alexander late 1970s
- A Pattern Language
- A Timeless Way of Building
- Design patterns capture the best practices of
experienced object-oriented software developers. - Design patterns are solutions to general software
development problems.
4Design Patterns
Patterns Elements Pattern Name
- In general, a pattern has four essential
elements. - The pattern name
- The problem
- The solution
- The consequences
5Design Patterns
Patterns Elements The Pattern Name
- The pattern name is a handle we can use to
describe a design problem, its solutions, and
consequences in a word or two. - Naming a pattern immediately increases the design
vocabulary. It lets us design at a higher level
of abstraction. - Having a vocabulary for patterns lets us talk
about them. - It makes it easier to think about designs and to
communicate them and their trade-offs to others.
6Design Patterns
Patterns Elements The Problem
- The problem describes when to apply the pattern.
-
- It explains the problem and its context.
- It might describe specific design problems such
as how to represent algorithms as objects. - It might describe class or object structures that
are symptomatic of an inflexible design. - Sometimes the problem will include a list of
conditions that must be met before it makes sense
to apply the pattern.
7Design Patterns
Patterns Elements The Solution
- The solution describes the elements that make up
the design, their relationships,
responsibilities, and collaborations. - The solution doesn't describe a particular
concrete design or implementation, because a
pattern is like a template that can be applied in
many different situations. - Instead, the pattern provides an abstract
description of a design problem and how a general
arrangement of elements (classes and objects in
our case) solves it.
8Design Patterns
Patterns Elements The Consequences
- The consequences are the results and trade-offs
of applying the pattern. - The consequences for software often concern space
and time trade-offs. - They may address language and implementation
issues as well. - Since reuse is often a factor in object-oriented
design, the consequences of a pattern include its
impact on a system's flexibility, extensibility,
or portability.
9Design Patterns
Types
- Erich Gamma, Richard Helm, Ralph Johnson and John
Vlisides in their Design Patterns gang of four
book define 23 design patterns divided into
three types - Creational patterns - create objects for you,
rather than having you instantiate objects
directly. This gives your program more
flexibility in deciding which objects need to be
created for a given case. - Structural patterns - help you compose groups of
objects into larger structures, such as complex
user interfaces or accounting data. - Behavioral patterns - help you define the
communication between objects in your system and
how the flow is controlled in a complex program.
10C Design Patterns
Creational Patterns and C I
- The creational patterns deal with the best way to
create instances of objects. - In C, the simplest ways to create an instance
of an object is by using the new operator or by
simply declaring the variable in the local scope - Fred fred1 new Fred() //instance of Fred
class - Fred fred2 //instance of Fred class
- The amount of hard coding depends on how you
create the object within your program. - In many cases, the exact nature of the object
that is created could vary with the needs of the
program and abstracting the creation process into
a special creator class can make your program
more flexible and general.
11C Design Patterns
Creational Patterns and C II
- The Factory Pattern provides a simple decision
making class that returns one of several possible
subclasses of an abstract base class depending on
the data that are provided. - The Abstract Factory Pattern provides an
interface to create and return one of several
families of related objects. - The Builder Pattern separates the construction of
a complex object from its representation. - The Prototype Pattern starts with an initialized
and instantiated class and copies or clones it to
make new instances rather than creating new
instances. - The Singleton Pattern is a class of which there
can be no more than one instance. It provides a
single global point of access to that instance.
12The Factory Pattern
How does it Work?
The Factory pattern returns an instance of one of
several possible classes depending on the data
provided to it.
- Here, x is a base class and classes xy and xz are
derived from it. - The Factory is a class that decides which of
these subclasses to return depending on the
arguments you give it. - The getClass() method passes in some value abc,
and returns some instance of the class x. Which
one it returns doesn't matter to the programmer
since they all have the same methods, but
different implementations.
13The Factory Pattern
The Shape Factory
class ShapeFactory public // Static
method to create objects // Change is
required only in this function static Shape
Create(string type) if ( type "circle"
) return new Circle() if ( type
"square" ) return new Square() return
NULL private //Constructor is made
private to prevent instantiation
ShapeFactory()
14The Factory Pattern
The Shape and Subclasses
//Superclass of all object that the Factory can
create class Shape public //common
interface to all subtypes virtual void
draw() 0 class Circle public
Shape public void draw() cout ltlt
"I am circle" ltlt endl class Square
public Shape public void draw()
cout ltlt "I am square" ltlt endl
15The Factory Pattern
The Driver client
int main() // Give me a circle Shape
shape1 ShapeFactoryCreate("circle") //
Give me a square Shape shape2
ShapeFactoryCreate("square")
shape1-gtdraw() // will call appropriate draw()
shape2-gtdraw() // as it is defined as virtual
delete shape1 delete shape2
16The Factory Pattern
When to Use a Factory Pattern
- You should consider using a Factory pattern when
- A class cant anticipate the kind of objects it
must create. - A class uses hierarchy of classes to specify
which objects it creates. - You want to localize the knowledge of which class
gets created. - How to recognize the Factory pattern?
- The base class is abstract and the pattern must
return a complete working class. - The base class contains default methods and is
only subclassed for cases where the default
methods are insufficient. - Parameters are passed to the factory telling it
which of several class types to return. In this
case the classes may share the same method names
but may do something quite different.
17The Abstract Factory Pattern
How does it Work?
- The Abstract Factory pattern is one level of
abstraction higher than the factory pattern. - This pattern returns one of several related
classes, each of which can return several
different objects on request. In other words, the
Abstract Factory is a factory object that returns
one of several factories. - One classic application of the abstract factory
is the case where your system needs to support
multiple look-and-feel user interfaces, such as
Windows, Linux or Macintosh - You tell the factory that you want your program
to look like Windows and it returns a GUI factory
which returns Windows-like objects. - When you request specific objects such as
buttons, check boxes and windows, the GUI factory
returns Windows instances of these visual
interface components.
18The Abstract Factory Pattern
A Widget Factory
// Superclass of all objects to be created by all
Factories class Widget public
//common interface to all created objects
virtual void draw() 0 //Supeclass of all
Factories class WidgetFactory public
//All specific kinds of objects that can be
created virtual Widget create_button()
0 virtual Widget create_menu() 0
19The Abstract Factory Pattern
The Motif Widget Factory
//Factory generating Motif Widgets class
MotifWidgetFactory public WidgetFactory
public Widget create_button() return new
MotifButton Widget create_menu()
return new MotifMenu //Different specific
kinds of Motif objects class MotifButton public
Widget public void draw() cout ltlt
"MotifButton\n" class MotifMenu public
Widget public void draw() cout ltlt
"MotifMenu\n"
20The Abstract Factory Pattern
The Windows Widget Factory
//Factory generating Windows Widgets class
WindowsWidgetFactory public WidgetFactory
public Widget create_button() return new
WindowsButton Widget create_menu()
return new WindowsMenu //Different
specific kinds of Windows objects class
WindowsButton public Widget public
void draw() cout ltlt "WindowsButton\n"
class WindowsMenu public Widget
public void draw() cout ltlt
"WindowsMenu\n"
21The Abstract Factory Pattern
The Driver client
//uncomment the following to generate Motif
widgets define MOTIF //uncomment the following
to generate Windows widgets //define
WINDOWS int main(int argc, char argv)
WidgetFactory widget_factory ifdef MOTIF
widget_factory new MotifWidgetFactory else //
WINDOWS widget_factory new
WindowsWidgetFactory endif Widget w2
widget_factory-gtcreate_button(),
widget_factory-gtcreate_menu()
w0-gtdraw() //call appropriate draw() method
w1-gtdraw() //of subclass of Widget object
22The Abstract Factory Pattern
Consequences of Abstract Factory
- One of the main purposes of the Abstract Factory
is that it isolates the concrete classes that are
generated. - The actual class names of these classes are
hidden in the factory and need not be known at
the client level at all. - Because of the isolation of classes, you can
change or interchange these product class
families freely. - Since you generate only one kind of concrete
class, this system keeps you for inadvertently
using classes from different families of
products. - While all of the classes that the Abstract
Factory generates have the same base class, there
is nothing to prevent some derived classes from
having additional methods that differ from the
methods of other classes.
23The Builder Pattern
How does it Work? - I
The Builder Pattern separates the construction of
a complex object from its representation so that
the same construction process can create
different representations.
- Builder - specifies an abstract interface for
creating parts of a Product object. - ConcreteBuilder - constructs and assembles parts
of the product by implementing the Builder
interface. Also, it defines and keeps track of
the representation it creates and provides an
interface for retrieving the product . - Director - constructs an object using the Builder
interface. - Product - represents the complex object under
construction.
24The Builder Pattern
How does it Work? - II
- The client creates the Director object and
configures it with the desired Builder object. - Director notifies the builder whenever a part of
the product should be built. - Builder handles requests from the director and
adds parts to the product. - The client retrieves the product from the
builder. - The following interaction diagram illustrates how
Builder and Director cooperate with a client.
25The Builder Pattern
Example Pizza Builder 5
//Superclass of all kinds of objects to be
created //Generically called Product class
Pizza public //Set all parts of the
Product, and use the Product void
setDough(const string dough) m_dough
dough void setSauce(const string sauce)
m_sauce sauce void setTopping(const
string topping) m_topping topping
void open() const cout ltlt "Pizza with "
ltlt m_dough ltlt " dough, " ltlt m_sauce
ltlt " sauce and " ltlt m_topping ltlt "
topping. Mmm." ltlt endl private //Parts
of the Product string m_dough string
m_sauce string m_topping
26The Builder Pattern
Example Pizza Builder 5
class PizzaBuilder public //get the
built Pizza from the Builder Pizza
getPizza() return m_pizza //build a
generic empty Pizza void createNewPizzaProduct
() m_pizza new Pizza //create each part
of the Product according to subtypes virtual
void buildDough() 0 virtual void
buildSauce() 0 virtual void buildTopping()
0 protected //Product built by Pizza
Builder Pizza m_pizza
27The Builder Pattern
Example Pizza Builder 5
class HawaiianPizzaBuilder public PizzaBuilder
//Concrete Builder 1 public virtual void
buildDough() //Build different
parts of the pizza m_pizza-gtsetDough("cros
s") //The construction process
could be virtual void buildSauce()
//more complex in a real-life example
m_pizza-gtsetSauce("mild")
//The construction of the pizza part virtual
void buildTopping() //depends on
the type of pizza. m_pizza-gtsetTopping("ha
mpineapple") class SpicyPizzaBuilder
public PizzaBuilder //Concrete Builder 2
public virtual void buildDough()
//The construction process may vary
m_pizza-gtsetDough("pan baked")
//across different Concrete Builders.
virtual void buildSauce()
m_pizza-gtsetSauce("hot") virtual void
buildTopping() m_pizza-gtsetTopping("peppero
nisalami") //There could be other Concrete
Builders added for other kinds of pizza the Chef
//designs later
28The Builder Pattern
Example Pizza Builder 5
class Cook //Director public void
setPizzaBuilder(PizzaBuilder pb) //Use a
concrete builder
//for building a specific
m_pizzaBuilder pb //kind of
Pizza. Pizza getPizza()
//get the constructed Pizza
return m_pizzaBuilder-gtgetPizza()
void constructPizza()
//Creational process to create
//a pizza using the
builder. m_pizzaBuilder-gtcreateNewPizzaP
roduct() m_pizzaBuilder-gtbuildDough()
m_pizzaBuilder-gtbuildSauce()
m_pizzaBuilder-gtbuildTopping()
private PizzaBuilder m_pizzaBuilder
29The Builder Pattern
Example Pizza Builder 5
//Pizza Builder Client int main() Cook
cook //Create the Director
PizzaBuilder hawaiianPizzaBuilder //Create
the Concrete Builder new HawaiianPizzaBuilder
PizzaBuilder spicyPizzaBuilder new
SpicyPizzaBuilder cook.setPizzaBuilder(
hawaiianPizzaBuilder) //Tell the Director
which Builder to use cook.constructPizza()
//Tell the Director to
construct the Product Pizza hawaiian
cook.getPizza() //Client gets the
Product hawaiian-gtopen()
//Client uses the Product
cook.setPizzaBuilder(spicyPizzaBuilder)
//same for another kind of product
cook.constructPizza() Pizza spicy
cook.getPizza() spicy-gtopen()
delete hawaiianPizzaBuilder delete
spicyPizzaBuilder delete hawaiian
delete spicy
30The Builder Pattern
Applicability of Builder Pattern
- Use the Builder pattern when
- The algorithm for creating a complex object
should be independent of the parts that make up
the object and how they are assembled. - The construction process must allow different
representations for the object that is
constructed.
31The Builder Pattern
Consequences of Builder Pattern
- A Builder lets you vary the internal
representation of the product it builds. It also
hides the details of how the product is
assembled. - Each specific builder is independent of the
others and of the rest of the program. This
improves modularity and makes the addition of
other builders relatively simple. - Because each builder constructs the final product
step-by-step, depending on the data, you have
more control over each final product that a
Builder constructs. - A Builder pattern is somewhat like an Abstract
Factory pattern in that both return classes made
up of a number of methods and objects. The main
difference is that while the Abstract Factory
returns a family of related classes, the Builder
constructs a complex object step by step
depending on the data presented to it.
32The Singleton Pattern
Definition Applicability - I
- Sometimes it is appropriate to have exactly one
instance of a class - window managers,
- print spoolers,
- filesystems.
- Typically, those types of objects known as
singletons, are accessed by disparate objects
throughout a software system, and therefore
require a global point of access. - The Singleton pattern addresses all the concerns
above. With the Singleton design pattern you can
- Ensure that only one instance of a class is
created. - Provide a global point of access to the object.
- Allow multiple instances in the future without
affecting a singleton class' clients.
33The Singleton Pattern
Definition Applicability - II
- The Singleton pattern ensures a class has only
one instance, and provides a global point of
access to it. - The class itself is responsible for keeping track
of its sole instance. The class can ensure that
no other instance can be created (by intercepting
requests to create new objects), and it can
provide a way to access the instance. - Singletons maintain a static reference to the
sole singleton instance and return a reference to
that instance from a static instance() method.
34The Singleton Pattern
The Classic Singleton - I
The Singleton class maintains a static reference
to the sinle singleton instance (s_instance) and
returns that reference from the static Instance()
method.
class SingletonClass private
int m_value //static instance, allows
static instance() method to access the instance
static SingletonClass s_instance
//private constructor prevents external
instantiation SingletonClass() m_value 0
public int get_value() return
m_value void increment_value()
m_value //static method to
create/access the singleton instance static
SingletonClass Instance() if
(!s_instance) s_instance new
SingletonClass() return s_instance
35The Singleton Pattern
The Classic Singleton - II
// Allocating and initializing SingletonClass's //
static data member. The pointer is being //
allocated - not the object itself. SingletonClass
SingletonClasss_instance 0 //two free
functions manipulating the instance void
foo(void) SingletonClassinstance()-gtincremen
t_value() cout ltlt "foo global_ptr is " ltlt
SingletonClassinstance()-gtget_value() ltlt
'\n' void bar(void) SingletonClassinstan
ce()-gtincrement_value() cout ltlt "bar
global_ptr is " ltlt SingletonClassinstance()-gtget
_value() ltlt '\n' int main(int argc, char
argv) cout ltlt "main global_ptr is " ltlt
SingletonClassinstance()-gtget_value() ltlt '\n'
foo() bar()
C Design Patterns
35
36The Singleton Pattern
The Classic Singleton - III
- The Singleton class employs a technique known as
lazy instantiation to create the singleton as a
result, the singleton instance is not created
until the Instance() method is called for the
first time. This technique ensures that singleton
instances are created only when needed. - The Singleton class implements a protected
constructor so clients cannot instantiate
Singleton instances. - Protected constructors can be called by
subclasses. - Solutions
- We can make the Singleton constructor private so
that only Singletons methods call it
37The Singleton Pattern
Consequences of the Singleton Pattern
- It can be difficult to subclass a Singleton,
since this can only work if the base Singleton
class has not yet been instantiated. - We can easily change a Singleton to allow a small
number of instances where this is allowable and
meaningful. - We can use the same approach to control the
number of instances that the application uses.
Only the operation that grants access to the
Singleton instance needs to change. - The Singleton pattern permits refinement of
operations and representation. The Singleton
class may be subclassed, and it is easy to
configure an application with an instance of this
extended class. You can configure the application
with an instance of the class you need at
run-time.
38Design Patterns
Structural Patterns
- Structural patterns describe how classes and
objects can be combined to form larger
structures. - The difference between class patterns and object
patterns is that class patterns describe how
inheritance can be used to provide more useful
program interfaces. - Object patterns, on the other hand, describe how
objects can be composed into larger structures
using object composition, or the inclusion of
objects within other objects. - Some of the Structural patterns are
- Adapter
- Composite
- Proxy
- Flyweight
- Façade
- Bridge
- Decorator
39Design Patterns
Structural Patterns - II
- The Adapter pattern can be used to make one class
interface match another to make programming
easier. - The Composite pattern is a composition of
objects, each of which may be either simple or
itself a composite object. - The Proxy pattern is frequently a simple object
that takes the place of a more complex object
that may be invoked later, for example when the
program runs in a network environment.
40Design Patterns
Structural Patterns III
- The Flyweight pattern is a pattern for sharing
objects, where each instance does not contain its
own state, but stores it externally. This allows
efficient sharing of objects to save space, when
there are many instances, but only a few
different types. - The Façade pattern is used to make a single class
represent an entire subsystem. - The Bridge pattern separates an objects
interface from its implementation, so you can
vary them separately. - The Decorator pattern can be used to add
responsibilities to objects dynamically.
41The Adapter Pattern
Definition Applicability - I
- Motivation
- Like any adapter in the real world it is used to
be an interface, a bridge between two objects
that have the same functionality, but that are to
be used in a different manner, i.e. have a
different specification to their interfaces. In
real world we have adapters for power supplies,
adapters for camera memory cards, and so on. - The same concept applies to software components.
You may have some class expecting some type of
object and you have an object offering the same
features, but exposing a different interface. You
don't want to change existing classes, so you
want to create an adapter. - Intent
- Convert the interface of a class into another
interface that clients expect. - Adapter lets classes work together, that could
not otherwise because of incompatible interfaces.
C Design Patterns
41
42The Adapter Pattern
Definition Applicability - II
- The classes/objects participating in adapter
pattern - Target - defines the domain-specific interface
that Client uses. - Adapter - adapts the interface Adaptee to the
Target interface. - Adaptee - defines an existing interface that
needs adapting. - Client - collaborates with objects conforming to
the Target interface.
C Design Patterns
42
C Design Patterns
42
43The Adapter Pattern
Definition Applicability - III
- The adapter pattern is used
- When you have a class (Target) that invokes
methods defined in an interface and you have a
another class (Adapter) that doesn't implement
the interface but implements the operations that
should be invoked from the first class through
the interface. You can change none of the
existing code. The adapter will implement the
interface and will be the bridge between the two
classes. - When you write a class (Target) for a generic use
relying on some general interfaces and you have
some implemented classes, not implementing the
interface, that needs to be invoked by the Target
class.
C Design Patterns
43
C Design Patterns
43
C Design Patterns
43
44The Adapter Pattern
Example - I
/ The SquarePeg class. This is the Target
class. / public class SquarePeg public void
insert(String str) cout ltlt "SquarePeg
insert() " ltlt str / The RoundPeg
class. This is the Adaptee class. / public
class RoundPeg public void insertIntoHole(Stri
ng msg) cout ltlt RoundPeg insertIntoHole() "
ltlt msg If a client only understands the
SquarePeg interface for inserting pegs using the
insert() method, how can it insert round pegs,
which are pegs, but that are inserted
differently, using the insertIntoHole() method?
C Design Patterns
44
C Design Patterns
44
C Design Patterns
44
C Design Patterns
44
45The Adapter Pattern
Example - II
Solution Design a RoundToSquarePeg adapter
that enables to insertIntoHole() a RoundPeg
object connected to the adapter to be inserted as
a SquarePeg, using insert(). / The
RoundToSquarePegAdapter class. This is the
Adapter class. It adapts a RoundPeg to a
SquarePeg. Its interface is that of a
SquarePeg. / public class RoundToSquarePegAdapter
public SquarePeg private RoundPeg roundPeg
public RoundToSquarePegAdapter(RoundPeg peg)
//the roundPeg is plugged into the adapter
this.roundPeg peg public void
insert(String str) //the roundPeg can now
be inserted in the same manner as a squarePeg!
roundPeg.insertIntoHole(str)
C Design Patterns
45
C Design Patterns
45
C Design Patterns
45
C Design Patterns
45
C Design Patterns
45
46The Adapter Pattern
Example - III
// Test program for Pegs. main(int argc, char
argv) // Create some pegs. RoundPeg
roundPeg new RoundPeg() SquarePeg
squarePeg new SquarePeg() // Do an insert
using the square peg. squarePeg.insert("Insert
ing square peg...") // Now we'd like to do
an insert using the round peg. // But this
client only understands the insert() //
method of pegs, not a insertIntoHole() method.
// The solution create an adapter that adapts
// a square peg to a round peg! PegAdapter
adapter new PegAdapter(roundPeg)
adapter.insert("Inserting round peg...")
SquarePeg sq_pegs2 new SquarePeg(),
new RoundToSquarePegAdapter(
roundPeg) sq_pegs0-gtinsertIntoSquareHole(
"Inserting square peg 0...\n")
sq_pegs1-gtinsertIntoSquareHole("Inserting
square peg 1...\n")
C Design Patterns
46
C Design Patterns
46
C Design Patterns
46
C Design Patterns
46
C Design Patterns
46
C Design Patterns
46
47The Adapter Pattern
Definition Applicability - VII
More two-way adapter! Solution multiple
inheritance! public class SquarePeg public
virtual void insertSquarePeg(String str) cout
ltlt "SquarePeg insertSquarePeg() " ltlt
str public class RoundPeg public virtual
void insertRoundPeg(String msg) cout ltlt
RoundPeg insertRoundPeg() " ltlt msg class
TwoWayPegAdapter public SquarePeg, RoundPeg
private RoundPeg roundPeg SquarePeg
squarePeg public TwoWayPegAdapter(RoundPe
g peg) //a roundPeg is plugged into the
adapter this.roundPeg peg
TwoWayPegAdapter(SquarePeg peg) //a
squarePeg is plugged into the adapter
this.squarePeg peg void virtual
insertRoundPeg(String str)
squarePeg.insertSquarePeg(str) void
virtual insertSquarePeg(String str)
roundPeg.insertRoundPeg(str)
C Design Patterns
47
C Design Patterns
47
C Design Patterns
47
C Design Patterns
47
C Design Patterns
47
C Design Patterns
47
C Design Patterns
47
48The Adapter Pattern
Definition Applicability - VIII
int main(int argc, char argv) RoundPeg
roundPeg new RoundPeg() SquarePeg
squarePeg new SquarePeg() SquarePeg
squarePegArray2 squarePeg,
new TwoWayPegAdapter(roundPeg)
squarePegArray0-gtinsertSquarePeg("Inserti
ng Square Peg in squarePegArray0...\n")
squarePegArray1-gtinsertSquarePeg("Inserting
Square Peg in squarePegArray1...\n")
RoundPeg roundPegArray2 roundPeg,
new
TwoWayPegAdapter(squarePeg)
roundPegArray0-gtinsertRoundPeg("Inserting Round
Peg in roundPegArray0...\n")
roundPegArray1-gtinsertRoundPeg("Inserting Round
Peg in roundPegArray1...\n")
C Design Patterns
48
C Design Patterns
48
C Design Patterns
48
C Design Patterns
48
C Design Patterns
48
C Design Patterns
48
C Design Patterns
48
C Design Patterns
48
49Design Patterns
Behavioral Patterns
- Observer pattern Define a one-to-many dependency
between objects so that when one object changes
state, all its dependents are notified and
updated automatically. - Null Object Provide an object as a surrogate for
the lack of an object of a given type. The Null
Object Pattern provides intelligent do nothing
behavior, hiding the details from its
collaborators. - Memento Capture the internal state of an object
without violating encapsulation and thus
providing a mean for restoring the object into
initial state when needed. - Observer Define a one-to-many dependency between
objects so that when one object changes state,
all its dependents are notified and updated
automatically.
C Design Patterns
49
50The Observer Pattern
Definition Applicability - I
Motivation The cases when certain objects need
to be informed about the changes occured in other
objects are frequent. To have a good design means
to decouple as much as possible and to reduce the
dependencies. The Observer Design Pattern can be
used whenever a subject has to be observed by one
or more observers. Intent Define a one-to-many
dependency between objects so that when one
object changes state, all its dependents are
notified and updated automatically. This pattern
is a cornerstone of the Model-View-Controller
architectural design, where the Model implements
the mechanics of the program, and the Views are
implemented as Observers that are as much
uncoupled as possible to the Model components.
C Design Patterns
50
C Design Patterns
50
C Design Patterns
50
C Design Patterns
50
C Design Patterns
50
C Design Patterns
50
C Design Patterns
50
C Design Patterns
50
51The Observer Pattern
Definition Applicability - II
C Design Patterns
51
C Design Patterns
51
C Design Patterns
51
C Design Patterns
51
C Design Patterns
51
C Design Patterns
51
C Design Patterns
51
C Design Patterns
51
C Design Patterns
51
C Design Patterns
51
52The Observer Pattern
Definition Applicability - III
The participants classes in the Observer pattern
are Observable - interface or abstract class
defining the operations for attaching and
de-attaching observers to the client. In the GOF
book this class/interface is known as
Subject. ConcreteObservable - concrete
Observable class. It maintain the state of the
observed object and when a change in its state
occurs it notifies the attached
Observers. Observer - interface or abstract
class defining the operations to be used to
notify the Observer object. ConcreteObserverA,
ConcreteObserverB - concrete Observer
implementations.
C Design Patterns
52
C Design Patterns
52
C Design Patterns
52
C Design Patterns
52
C Design Patterns
52
C Design Patterns
52
C Design Patterns
52
C Design Patterns
52
C Design Patterns
52
53The Observer Pattern
Definition Applicability - IV
- Behavior
- The client class instantiates the
ConcreteObservable object. - Then it instantiate and attaches the concrete
observers to it using the methods defined in the
Observable interface. - Each time the state of the subject it's changing
it notifies all the attached Observers using the
methods defined in the Observer interface. - When a new Observer is added to the application,
all we need to do is to instantiate it in the
client class and to add attach it to the
Observable object. - The classes already created will remain
unchanged.
C Design Patterns
53
C Design Patterns
53
C Design Patterns
53
C Design Patterns
53
C Design Patterns
53
C Design Patterns
53
C Design Patterns
53
C Design Patterns
53
C Design Patterns
53
C Design Patterns
53
54The Observer Pattern
Example - I
- // Subject class, also known as Observable
- //
- class Observable
-
- public
- virtual Observable()
- virtual void attach(Observer )
- virtual void detach(Observer )
- virtual void notify()
- protected
- Observable()
- private
- listltObservergt _observers
-
C Design Patterns
54
C Design Patterns
54
C Design Patterns
54
C Design Patterns
54
C Design Patterns
54
C Design Patterns
54
C Design Patterns
54
C Design Patterns
54
C Design Patterns
54
C Design Patterns
54
C Design Patterns
54
55The Observer Pattern
Example - II
// A Sub-class of Observable a Clock
Timer // class ClockTimer public Observable
public ClockTimer() int
GetHour()return hour int
GetMinute()return minute int
GetSecond()return second void
tick() // update internal time-keeping
state // ... // The Observable object
notifies all its registered observers
notify() private int hour int
minute int second In green are the
changes to be applied to the class to be made an
observable class.
C Design Patterns
55
C Design Patterns
55
C Design Patterns
55
C Design Patterns
55
C Design Patterns
55
C Design Patterns
55
C Design Patterns
55
C Design Patterns
55
C Design Patterns
55
C Design Patterns
55
C Design Patterns
55
C Design Patterns
55
56The Observer Pattern
Example - III
//Observer Class // class Observer public
virtual Observer() virtual void
Update(Subject theChangeSubject) 0
protected Observer() The Observer
class is a virtual class
C Design Patterns
56
C Design Patterns
56
C Design Patterns
56
C Design Patterns
56
C Design Patterns
56
C Design Patterns
56
C Design Patterns
56
C Design Patterns
56
C Design Patterns
56
C Design Patterns
56
C Design Patterns
56
C Design Patterns
56
C Design Patterns
56
57The Observer Pattern
Example - IV
// A specific Observer to observe ClockTimers
DigitalClock // class DigitalClock public
Observer public DigitalClock(ClockTimer
s) //Upon instantiation, attaches
itself to a ClockTimer _observable s
_observable-gtattach(this) DigitalClock(
) //Upon destruction, detaches itself
from its ClockTimer _observable-gtdetach(this
) void Update(Subject
theChangedSubject) //if the notification
concerns my own subject, redraw my clocks
reading if(theChangedSubject
_observable) draw() void
draw() int hour _subject-gtGetHour()
int minute _subject-gtGetMinute()
int second _subject-gtGetSecond() cout ltlt
hour ltlt '' ltlt minute ltlt '' ltlt second ltlt endl
private ClockTimer _observable
C Design Patterns
57
C Design Patterns
57
C Design Patterns
57
C Design Patterns
57
C Design Patterns
57
C Design Patterns
57
C Design Patterns
57
C Design Patterns
57
C Design Patterns
57
C Design Patterns
57
C Design Patterns
57
C Design Patterns
57
C Design Patterns
57
C Design Patterns
57
58The Observer Pattern
Example - V
int main(void) //Create a ClockTimer to be
observed ClockTimer timer new ClockTimer
//Create a DigitalClock that is connected to the
ClockTimer DigitalClock digitalClock new
DigitalClock(timer) //Advancing the
ClockTimer updates the DigitalClock //as Tick()
calls Update() after it changed its state
while(true) timer-gttick()
C Design Patterns
58
C Design Patterns
58
C Design Patterns
58
C Design Patterns
58
C Design Patterns
58
C Design Patterns
58
C Design Patterns
58
C Design Patterns
58
C Design Patterns
58
C Design Patterns
58
C Design Patterns
58
C Design Patterns
58
C Design Patterns
58
C Design Patterns
58
59Resources
- 1 Christopher Alexander, Sara Ishikawa, Murray
Silverstein, Max Jacobson, Ingrid Fiksdahl-King,
and Shlomo Angel. A Pattern Language. Oxford
University Press, New York, 1977. - 2 Erich Gamma, Richard Helm, Ralph Johnson and
John Vlissides, Design Patterns Elements of
Reusable Object-Oriented Software,
Adisson-Wesley, 1995. - 3 James W. Cooper, The Design Patterns Java
Companion Elements of Reusable Object-Oriented
Software, Adisson-Wesley, 1998. - 4 James O. Coplien, Advanced C Programming
Styles and Idioms, Addison-Wesley, Reading, MA.,
1992. - 5 www.oodesign.com. Object-oriented design
patterns. 2009. - 6 C Programming WikiBook
- http//en.wikibooks.org/wiki/C_Programming/Code
/Design_Patterns/Creational_Patterns