GoF Design Patterns
GoF Design Patterns
“Gang of Four” Design Patterns
• Adapter
• Factory
• Singleton
• Observer (Publish-Subscribe)
Adapter Pattern
Problem: How to resolve incompatible interfaces,
or how to provide a stable interface to similar
components with different interfaces.
Solution: Convert the original interface of a
component into another interface, through an
intermediate adapter object.
Note: the Adapter pattern is an application of
Polymorphism
Adapter Pattern
Example: POS needs to adapt several kinds
of external third-party services: tax
calculators, credit authorization services,
inventory systems, accounting systems.
Each has a different API which can’t be
changed.
«interface» Adapters use interfaces and
ITaxCalculatorAdapter polymorphism to add a level of
indirection to varying APIs in other
getTaxes( Sale ) : List of TaxLineItems components.
TaxMasterAdapter GoodAsGoldTaxPro
Adapter
getTaxes( Sale ) : List of TaxLineItems
getTaxes( Sale ) : List of TaxLineItems
«interface» «interface»
IAccountingAdapter ICreditAuthorizationService
Adapter
postReceivable( CreditPayment )
postSale( Sale ) requestApproval(CreditPayment,TerminalID, MerchantID)
... ...
«interface»
IInventoryAdapter
SAPAccountingAdapter GreatNorthernAccountingAdapter
...
postReceivable( CreditPayment ) postReceivable( CreditPayment )
postSale( Sale ) postSale( Sale )
... ...
:Register : SAPAccountingAdapter
makePayment
...
SOAP over
HTTP
postSale( sale )
xxx «actor»
: SAPSystem
the Adapter adapts to
interfaces in other components
Adapter Pattern
Note: Adapter pattern follows GRASP
principles: Polymorphism, Protected
Variation, Indirection
conceptual connection among GRASP
principles and Adapter pattern
Conceptual connection among GRASP principles and Adapter
pattern
Low coupling is a way to achieve protection at a Protected Variation GRASP
variation point. Mechanism Principles
Polymorphism is a way to achieve protection at a
variation point, and a way to achieve low coupling.
An indirection is a way to achieve low coupling. Low Coupling High Cohesion
Mechanism Mechanism
The Adapter design pattern is a kind of Indirection
and a Pure Fabrication, that uses Polymorphism.
Polymorphism Indirection Pure
Example Mechanism Fabrication
GoF Design
Adapter Patterns
Factory Pattern
Problem: Who should be responsible for
creating objects when there are special
considerations such as complex creation
logic, a desire to separate creation
responsibilities for better cohesion, etc.?
Solution: Create a Pure Fabrication object
called a Factory that handles the creation.
Factory Pattern
• Technically not a GoF pattern
• A variation of GoF Abstract Factory
pattern
Fig. 26.5
ServicesFactory note that the factory methods
return objects typed to an
accountingAdapter : IAccountingAdapter interface rather than a class, so
inventoryAdapter : IInventoryAdapter that the factory can return any
taxCalculatorAdapter : ITaxCalculatorAdapter implementation of the interface
getAccountingAdapter() : IAccountingAdapter
getInventoryAdapter() : IInventoryAdapter
getTaxCalculatorAdapter() : ITaxCalculatorAdapter
...
if ( taxCalculatorAdapter == null )
{
// a reflective or data-driven approach to finding the right class: read it from an
// external property
String className = System.getProperty( "taxcalculator.class.name" );
taxCalculatorAdapter = (ITaxCalculatorAdapter) Class.forName( className ).newInstance();
}
return taxCalculatorAdapter;
Factory Pattern (26.4)
Note: In Fig. 26.5 the implementation of
ServicesFactory illustrates data-driven
design – a form of Protected Variation
Factory Pattern (26.4)
Idea: Define an object whose purpose is to
create objects
Benefits:
– Separate the responsibility of complex
creation into cohesive helper objects
– Can provide object caching (e.g. having only
one random number generator)
Singleton Pattern (26.5)
Problem: Exactly one instance of a class is
allowed. Objects need a global and single
point of access.
Solution: Define a static method of the
class that returns the singleton:
getInstance()
Singleton Pattern (26.5)
Consider the factory and how it is accessed – who creates
the factory?
– Only want one instance of the factory
– Methods may need to be called from various places => how to
make single instance of the factory globally visible
Could pass the ServicesFactory instance around as a
parameter whenever visibility is required or initialize all
objects that need it with a permanent reference to it
Singleton – supports global visibility or a single access
point to a single instance
Fig. 26.6
UML notation: this '1' can optionally be used to
indicate that only one instance will be created (a
singleton)
1
ServicesFactory
UML notation: in a instance : ServicesFactory singleton static
class box, an attribute
underlined attribute or accountingAdapter : IAccountingAdapter
method indicates a inventoryAdapter : IInventoryAdapter
static (class level) taxCalculatorAdapter : ITaxCalculatorAdapter
member, rather than singleton
an instance member getInstance() : ServicesFactory static
method
getAccountingAdapter() : IAccountingAdapter
getInventoryAdapter() : IInventoryAdapter
getTaxCalculatorAdapter() : ITaxCalculatorAdapter
...
// static method
public static synchronized ServicesFactory getInstance()
{
if ( instance == null )
instance = new ServicesFactory()
return instance
}
Singleton Pattern (26.5)
Note: concurrency control in
ServicesFactory – making getInstance()
synchronized
Fig. 26.8 shows how Adapter, Factory,
Singleton patterns are used in design
Fig. 26.8 1
:Store
:ServicesFactory
create
create :Register
accountingAdapter =
getAccountingAdapter
create : SAPAccounting
Adapter
accountingAdapter:
:Register
SAPAccountingAdapter
makePayment
create(cashTendered) : Payment SOAP over
HTTP
postSale( sale )
xxx «actor»
: SAPSystem
Observer Pattern (26.10)
Also known as Publish-Subscribe Pattern
Problem: Different kinds of subscriber objects are
interested in state changes or events of a publisher
object and want to react in their own unique way when
the publisher generates an event. The publisher wants
to maintain low coupling to the subscribers.
Solution: Define a subscriber or listener interface.
Subscribers implement the interface. The publisher can
dynamically register subscribers who are interested in an
event and notify them when an event occurs.
Observer Pattern (26.10)
Example: Want a GUI window to refresh
(update) its display of sale total when the
total changes
See Fig. 26.21
Fig. 26.21
Goal: When the total of the sale
changes, refresh the display with
the new value
Sale
total
...
setTotal( newTotal )
...
Observer Pattern (26.10)
Example (cont):
Simple solution – when Sale changes its
total the object sends a message to the
window telling it to refresh its display
Problem – high coupling between domain
objects and UI objects
Observer Pattern (26.10)
Example (cont):
Want to be able to easily replace UI
objects or even add other UI objects that
can be notified of this event
That is, want model-view separation
Model objects shouldn’t know about view
objects => Protected Variations with
respect to a changing user interface
Fig. 26.22
{ {
for each PropertyListener pl in propertyListeners propertyListeners.add( lis );
pl.onPropertyEvent( this, name, value ); }
}
Sale
addPropertyListener( PropertyListener lis )
publishPropertyEvent( name, value )
setTotal( Money newTotal )
...
{
total = newTotal;
publishPropertyEvent( "sale.total", total );
}
javax.swing.JFrame propertyListeners
*
... «interface»
setTitle() PropertyListener
setVisible()
... onPropertyEvent( source, name, value )
{
if ( name.equals("sale.total") )
saleTextField.setText( value.toString() );
}
SaleFrame1
onPropertyEvent( source, name, value ) {
sale.addPropertyListener( this )
initialize( Sale sale ) ...
... }
Observer Pattern (26.10)
Steps (p. 465)
1. Define an interface PropertyListener with operation
onPropertyEvent
2. Define window (SaleFrame1) to implement the interface
3. When SaleFrame1 is initialized pass it the Sale instance from
which it is displaying the total
4. SaleFrame1 registers to the Sale instance for notification of
“property events” via the addPropertyListener message
5. Note that the Sale does not know about SaleFrame1 objects; it
only knows about objects that implement the PropertyListener
interface. (This lowers the coupling of the Sale to the window
– the coupling is only to an interface, not to a GUI class.)
6. The Sale instance is the publisher of “property events”. When
the total changes, it iterates across all subscribing
PropertyListeners, notifying each
Observer Pattern (26.10)
Notes:
– The SaleFrame1 object is the
observer/subscriber/listener
– Sale is the publisher of property events
– Sale adds SaleFrame1 object to its list of
PropertyListener subscribers – Fig. 26.23
Fig. 26.23
sf : SaleFrame1 propertyListeners :
s : Sale
List<PropertyListener>
initialize( s : Sale )
addPropertyListener( sf )
add( sf )
Observer Pattern (26.10)
Notes:
– When the Sale total changes it iterates over
all registered subscribers and sends the
onPropertyEvent message to each – Figs.
26.24, 26.25
Fig. 26.24
s :Sale propertylisteners[ i ] :
PropertyListener
setTotal( total )
publishPropertyEvent
( "sale.total", total )
loop onPropertyEvent( s, "sale.total", total )
Fig. 26.25
Since this is a polymorphic operation implemented by
this class, show a new interaction diagram that starts saleTextField
: SaleFrame1
with this polymorphic version : JTextField
onPropertyEvent( source, name, value )
setText( value.toString() )
UML notation: Note this little expression within the
parameter. This is legal and consise.
Fig. 26.26
Sale
addPropertyListener( PropertyListener lis ) publishes events to
publishPropertyEvent( name, value ) observers/listeners/
subscribers
setTotal( Money newTotal ) registers them when
... they ask to subscribe
javax.swing.JFrame propertyListeners
*
... «interface»
setTitle() PropertyListener
setVisible()
... onPropertyEvent( source, name, value )
listens for events
SaleFrame1 observes events
subscribes to notification of events
onPropertyEvent( source, name, value )
initialize( Sale sale )
...
Who is the observer, listener, subscriber, and publisher?
Observer Pattern (26.10)
Notes:
– Sale is coupled to view object but only loosely since it
only knows subscribers as implementing the
PropertyListener interface
– In Java this was called Delegation Event Model
Observer pattern is basis for GUI widget event
handling in both Java (AWT & Swing) and .NET
Widgets are publishers of events, other objects
can register as listeners
Observer Pattern (26.10)
Example of AlarmClock:
AlarmClock is publisher of alarm events
Different types of objects can register as
listeners and react to same alarm event in
their own ways
Fig. 26.27
{
for each AlarmListener al in alarmListeners
al.onAlarmEvent( this, time );
} {
alarmListeners.add( lis );
}
AlarmClock
addAlarmnListener( AlarmListener lis )
publishAlarmEvent( time )
setTime( newTime ) {
... time = newTime;
if ( time == alarmTime )
publishAlarmEvent( time );
}
javax.swing.JFrame alarmListeners
*
... «interface»
setTitle() AlarmListener
setVisible()
... onAlarmEvent( source, time )
AlarmWindow Beeper ReliabilityWatchDog
onAlarmEvent( source, time ) onAlarmEvent( source, time ) onAlarmEvent( source, time )
... ... ...
{ {
{
display notification dialog check that all required processes
beep
box are executing normally
}
} }
Summary
• Singleton:
– Factory for a singular (sole) instance
– Ensures that only one object of a particular class is
ever created.
• Adapter:
– Translator adapts a server interface for a client
– Used to provide link between two or incompatible
types by wrapping with a class that supports the
interface required by the client.
Observer Pattern:
– Used to allow an object to publish changes to its
state.
– Other objects subscribe to be immediately notified
of any changes.
– Dependents update automatically when subject
changes
• Factory:
– Factory for building related objects
– Used to provide client with a set of related and
dependent objects.