gof design patterns (ch. 26)

59
GoF Design Patterns (Ch. 26)

Upload: ganya

Post on 02-Feb-2016

63 views

Category:

Documents


3 download

DESCRIPTION

GoF Design Patterns (Ch. 26). GoF Design Patterns. Adapter Factory Singleton Strategy Composite Façade Observer (Publish-Subscribe). Adapter Pattern (26.1). - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: GoF Design Patterns (Ch. 26)

GoF Design Patterns (Ch. 26)

Page 2: GoF Design Patterns (Ch. 26)

GoF Design Patterns

• Adapter

• Factory

• Singleton

• Strategy

• Composite

• Façade

• Observer (Publish-Subscribe)

Page 3: GoF Design Patterns (Ch. 26)

Adapter Pattern (26.1)

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

Page 4: GoF Design Patterns (Ch. 26)

Adapter Pattern (26.1)

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.

Page 5: GoF Design Patterns (Ch. 26)

Fig. 26.1

TaxMasterAdapter

getTaxes( Sale ) : List of TaxLineItems

GoodAsGoldTaxProAdapter

getTaxes( Sale ) : List of TaxLineItems

«interface»ITaxCalculatorAdapter

getTaxes( Sale ) : List of TaxLineItems

Adapters use interfaces and polymorphism to add a level of indirection to varying APIs in other components.

SAPAccountingAdapter

postReceivable( CreditPayment )postSale( Sale )...

GreatNorthernAccountingAdapter

postReceivable( CreditPayment )postSale( Sale )...

«interface»IAccountingAdapter

postReceivable( CreditPayment )postSale( Sale )...

«interface»IInventoryAdapter

...

«interface»ICreditAuthorizationService

Adapter

requestApproval(CreditPayment,TerminalID, MerchantID)...

Page 6: GoF Design Patterns (Ch. 26)

Fig. 26.2

:Register : SAPAccountingAdapter

postSale( sale )

makePayment

the Adapter adapts to interfaces in other components

SOAP over HTTP

xxx

...

«actor»: SAPSystem

Page 7: GoF Design Patterns (Ch. 26)

Adapter Pattern (26.1)

Note: Adapter pattern follows GRASP principles: Polymorphism, Protected Variation, Indirection

See Fig. 26.3 for conceptual connection among GRASP principles and Adapter pattern

Page 8: GoF Design Patterns (Ch. 26)

Fig. 26.3

Low coupling is a way to achieve protection at a variation point.

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.

The Adapter design pattern is a kind of Indirection and a Pure Fabrication, that uses Polymorphism.

Protected VariationMechanism

Low Coupling Mechanism

IndirectionMechanism

Adapter

Pure Fabrication

PolymorphismExample

GoF Design Patterns

GRASP Principles

High CohesionMechanism

Page 9: GoF Design Patterns (Ch. 26)

Factory Pattern (26.4)

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.

Page 10: GoF Design Patterns (Ch. 26)

Factory Pattern (26.4)

• Technically not a GoF pattern

• A variation of GoF Abstract Factory pattern

Page 11: GoF Design Patterns (Ch. 26)

Fig. 26.5

ServicesFactory

accountingAdapter : IAccountingAdapterinventoryAdapter : IInventoryAdaptertaxCalculatorAdapter : ITaxCalculatorAdapter

getAccountingAdapter() : IAccountingAdaptergetInventoryAdapter() : IInventoryAdaptergetTaxCalculatorAdapter() : ITaxCalculatorAdapter...

note that the factory methods return objects typed to an interface rather than a class, so that the factory can return any implementation of the interface

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;

Page 12: GoF Design Patterns (Ch. 26)

Factory Pattern (26.4)

Note: In Fig. 26.5 the implementation of ServicesFactory illustrates data-driven design – a form of Protected Variation

Page 13: GoF Design Patterns (Ch. 26)

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)

Page 14: GoF Design Patterns (Ch. 26)

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()

Page 15: GoF Design Patterns (Ch. 26)

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

Page 16: GoF Design Patterns (Ch. 26)

Fig. 26.6

1ServicesFactory

instance : ServicesFactory

accountingAdapter : IAccountingAdapterinventoryAdapter : IInventoryAdaptertaxCalculatorAdapter : ITaxCalculatorAdapter

getInstance() : ServicesFactory

getAccountingAdapter() : IAccountingAdaptergetInventoryAdapter() : IInventoryAdaptergetTaxCalculatorAdapter() : ITaxCalculatorAdapter...

singleton static attribute

singleton static method

// static methodpublic static synchronized ServicesFactory getInstance(){if ( instance == null ) instance = new ServicesFactory()return instance}

UML notation: in a class box, an underlined attribute or method indicates a static (class level) member, rather than an instance member

UML notation: this '1' can optionally be used to indicate that only one instance will be created (a singleton)

Page 17: GoF Design Patterns (Ch. 26)

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

Page 18: GoF Design Patterns (Ch. 26)

Fig. 26.8

:Register accountingAdapter: SAPAccountingAdapter

postSale( sale )

makePayment

SOAP over HTTP

xxx

:Register

1:ServicesFactory

accountingAdapter = getAccountingAdapter

:Store

createcreate

: SAPAccountingAdapter

: Paymentcreate(cashTendered)

«actor»: SAPSystem

create

Page 19: GoF Design Patterns (Ch. 26)

Strategy Pattern (26.7)

Problem: How to design for varying but related algorithms or policies? How to design for the ability to change these algorithms or policies?

Solution: Define each algorithm/strategy in a separate class with a common interface

Page 20: GoF Design Patterns (Ch. 26)

Strategy Pattern (26.7)

Example: How to provide more complex pricing logic, e.g. store-wide discount, senior citizen discount, employee discount, etc.

A pricing strategy for a sale can vary, how do we design for these varying pricing algorithms?

Page 21: GoF Design Patterns (Ch. 26)

Fig. 26.9

PercentDiscountPricingStrategy

percentage : float

getTotal( s:Sale ) : Money

AbsoluteDiscountOverThresholdPricingStrategy

discount : Moneythreshold : Money

getTotal( s:Sale ) : Money

«interface»ISalePricingStrategy

getTotal( Sale ) : Money

{ return s.getPreDiscountTotal() * percentage }

???PricingStrategy

...

...

{pdt := s.getPreDiscountTotal() if ( pdt < threshold ) return pdtelse return pdt - discount }

Page 22: GoF Design Patterns (Ch. 26)

Strategy Pattern (26.7)

Example: Create multiple SalePricingStrategy classes each with a polymorphic getTotal() operation

Note: each getTotal() operation takes a Sale object as a parameter so that the strategy object can find the pre-discount price from the Sale

The implementation of each getTotal() will differ

A strategy object is attached to a context object – the object to which it applies the algorithm, e.g. Sale

Page 23: GoF Design Patterns (Ch. 26)

Fig. 26.10

:PercentDiscountPricingStrategy

s : Sale

st = getSubtotal

t = getTotal

lineItems[ i ] :SalesLineItem

t = getTotal( s )

pdt = getPreDiscountTotal

{ t = pdt * percentage }

note that the Sale s is passed to the Strategy so that it has parameter visibility to it for further collaboration

loop

Page 24: GoF Design Patterns (Ch. 26)

Strategy Pattern (26.7)

Example:– When a getTotal() message is sent to a Sale it

delegates work to its strategy object– It is common for the context object to pass a

reference to itself to the strategy object so that the strategy object has parameter visibility to the context object

Page 25: GoF Design Patterns (Ch. 26)

Fig. 26.11

PercentDiscountPricingStrategy

percentage : float

getTotal( Sale ) : Money

AbsoluteDiscountOverThresholdPricingStrategy

discount : Moneythreshold : Money

getTotal( Sale ) : Money

«interface»ISalePricingStrategy

getTotal( Sale ) : Money

Sale

date...

getTotal()...

1

Sale needs attribute visibility to its Strategy

pricingStrategy

getTotal(){...return pricingStrategy.getTotal( this )

}

Page 26: GoF Design Patterns (Ch. 26)

Strategy Pattern (26.7)

Example: Who should create the strategy?– Apply the Factory pattern: a

PricingStrategyFactory– The PricingStrategyFactory is a singleton and

accessed via the Singleton pattern

Page 27: GoF Design Patterns (Ch. 26)

Fig. 26.12

1PricingStrategyFactory

instance : PricingStrategyFactory

getInstance() : PricingStrategyFactory

getSalePricingStrategy() : ISalePricingStrategygetSeniorPricingStrategy() : ISalePricingStrategy...

{ String className = System.getProperty( "salepricingstrategy.class.name" ); strategy = (ISalePricingStrategy) Class.forName( className ).newInstance(); return strategy; }

Page 28: GoF Design Patterns (Ch. 26)

Fig. 26.13

:Sale

1:PricingStrategyFactory

ps =getSalePricingStrategy

:Register

makeNewSalecreate

create(percent) ps : PercentDiscountPricingStrategy

Page 29: GoF Design Patterns (Ch. 26)

Strategy Pattern (26.7)

Note:– Strategy is based on Polymorphism and

provides Protected Variation with respect to changing algorithms

– Strategies are often/usually created by a Factory

Page 30: GoF Design Patterns (Ch. 26)

Composite Pattern (26.8)

Problem: How to treat a group or composition structure of objects the same way (polymorphically) as a non-composite (atomic) object?

Solution: Define classes for composite and atomic objects so that they implement the same interface.

Page 31: GoF Design Patterns (Ch. 26)

Composite Pattern (26.8)

Design problem: How to handle multiple conflicting pricing policies?

Example:– 20% senior discount– Preferred customer discount of 15% off sales over

$400– On Monday, there is a $50 off purchases over $500– Buy one case of Darjeeling tea, get 15% discount off

everything

Page 32: GoF Design Patterns (Ch. 26)

Composite Pattern (26.8)

Example (cont.): Pricing strategies determined by– Time period (Monday)– Customer type (senior)– Line item product (Darjeeling tea)In addition to pre-discount price

• May have multiple co-existing strategies• Customer type and type of product may need to

be known at time strategy is created (i.e. known by StrategyFactory)

Page 33: GoF Design Patterns (Ch. 26)

Composite Pattern (26.8)

Example (cont.): Now how do we design so that the Sale object does not know if it is dealing with one or many pricing strategies and also offer a design for the conflict resolution

Composite pattern!

Page 34: GoF Design Patterns (Ch. 26)

Composite Pattern (26.8)

Key feature: – The composite object contains a list of inner

objects and both the composite object and the inner objects implement the same interface

Page 35: GoF Design Patterns (Ch. 26)

Fig. 26.14

PercentageDiscountPricingStrategy

percentage : float

getTotal( Sale ) : Money

AbsoluteDiscountOverThresholdPricingStrategy

discount : Moneythreshold : Money

getTotal( Sale ) : Money

«interface»ISalePricingStrategy

getTotal( Sale ) : Money

{ return sale.getPreDiscountTotal() * percentage }

CompositePricingStrategy

add( ISalePricingStrategy )getTotal( Sale ) : Money

{lowestTotal = INTEGER.MAXfor each ISalePricingStrategy strat in pricingStrategies { total := strat.getTotal( sale ) lowestTotal = min( total, lowestTotal ) }return lowestTotal }

1..*

CompositeBestForCustomerPricingStrategy

getTotal( Sale ) : Money

CompositeBestForStorePricingStrategy

getTotal( Sale ) : Money

strategies

All composites maintain a list of contained strategies. Therefore, define a common superclass CompositePricingStrategy that defines this list (named strategies).

Sale

date...

getTotal()...

1

pricingStrategy

{...return pricingStrategy.getTotal( this )}

Page 36: GoF Design Patterns (Ch. 26)

Composite Pattern (26.8)

The Sale object treats a Composite Strategy that contains other strategies as any object that implements ISalePricingStrategy (i.e., calls its getTotal(s) operation)

See code pp. 455-456

Notation for abstract classes and abstract methods – see Fig. 26.16

Page 37: GoF Design Patterns (Ch. 26)

Fig. 26.16

CompositePricingStrategy

add( ISalePricingStrategy )getTotal( Sale ) : Money

CompositeBestForCustomerPricingStrategy

getTotal( Sale ) : Money

CompositeBestForStorePricingStrategy

getTotal( Sale ) : Money

UML notation: An abstract class is shown with an italicized name

abstract methods are also shown with italics

Page 38: GoF Design Patterns (Ch. 26)

Façade Pattern (26.9)

Problem: A common unified interface to a disparate set of implementations or interfaces – such as within a subsystem – is required. There may be undesirable coupling to many things in the subsystem, or the implementation of the subsystem may change. What to do?

Solution: Define a single point of contact to the subsystem – a façade that wraps the subsystem. This façade object presents a single unified interface and is responsible for collaborating with the subsystem components.

Page 39: GoF Design Patterns (Ch. 26)

Façade Pattern (26.9)

A façade object serves as a “front-end” object that is the single point of entry for the services of a subsystem

Façade provides Protected Variation from changes in the implementation of the subsystem

Page 40: GoF Design Patterns (Ch. 26)

Façade Pattern (26.9)

Example: A “rule engine” subsystem – responsible for evaluating a set of rules against an operation and indicating if any rules invalidate the operation

Example of a rule: If the sale is paid by a gift certificate, invalidate all payment types of change due back to the customer except for another gift certificate.

Also known as pluggable business rules

Page 41: GoF Design Patterns (Ch. 26)

Façade Pattern (26.9)

Example (cont): Define a façade object to this subsystem: POSRuleEngineFacade

Calls to this façade placed near the start of methods that are points for pluggable rules, see code p. 462

The hidden subsystem could contain any number of rules

Page 42: GoF Design Patterns (Ch. 26)

Fig. 26.20

Domain

+ Sale + Register ...

POSRuleEngine

«interface»- IRule

...

- Rule1

...

- Rule2

...

...

package name may be shown in the tab

visibility of the package element (to outside the package) can be shown by preceding the element name with a visibility symbol

+ POSRuleEngineFacade

instance : RuleEngineFacade

getInstance() : RuleEngineFacade

isInvalid( SalesLineItem, Sale )isInvalid( Payment, Sale )...

*

Page 43: GoF Design Patterns (Ch. 26)

Façade Pattern (26.9)

Notes: – Façade is usually accessed via Singleton– Similar to Adapter but Adapter applies to

varying interfaces not hiding implementation of subsystem

Page 44: GoF Design Patterns (Ch. 26)

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.

Page 45: GoF Design Patterns (Ch. 26)

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

Page 46: GoF Design Patterns (Ch. 26)

Fig. 26.21

Goal: When the total of the sale changes, refresh the display with the new value

Sale

total...

setTotal( newTotal )...

Page 47: GoF Design Patterns (Ch. 26)

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

Page 48: GoF Design Patterns (Ch. 26)

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 separationModel objects shouldn’t know about view objects => Protected Variations with respect to a changing user interface

Page 49: GoF Design Patterns (Ch. 26)

Fig. 26.22

«interface»PropertyListener

onPropertyEvent( source, name, value )

SaleFrame1

onPropertyEvent( source, name, value )

initialize( Sale sale )...

javax.swing.JFrame

...setTitle()setVisible()...

{ if ( name.equals("sale.total") ) saleTextField.setText( value.toString() );}

Sale

addPropertyListener( PropertyListener lis )publishPropertyEvent( name, value )

setTotal( Money newTotal )...

*propertyListeners

{ total = newTotal; publishPropertyEvent( "sale.total", total ); }

{ propertyListeners.add( lis );}

{ for each PropertyListener pl in propertyListeners pl.onPropertyEvent( this, name, value ); }

{ sale.addPropertyListener( this ) ... }

Page 50: GoF Design Patterns (Ch. 26)

Observer Pattern (26.10)

Steps (p. 465)1. Define an interface PropertyListener with operation

onPropertyEvent2. Define window (SaleFrame1) to implement the interface3. When SaleFrame1 is initialized pass it the Sale instance from

which it is displaying the total4. SaleFrame1 registers to the Sale instance for notification of

“property events” via the addPropertyListener message5. 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

Page 51: GoF Design Patterns (Ch. 26)

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

Page 52: GoF Design Patterns (Ch. 26)

Fig. 26.23

s : Salesf : SaleFrame1

initialize( s : Sale )

addPropertyListener( sf )

propertyListeners : List<PropertyListener>

add( sf )

Page 53: GoF Design Patterns (Ch. 26)

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

Page 54: GoF Design Patterns (Ch. 26)

Fig. 26.24

s :Sale

setTotal( total )

onPropertyEvent( s, "sale.total", total )

publishPropertyEvent( "sale.total", total )

propertylisteners[ i ] : PropertyListener

loop

Page 55: GoF Design Patterns (Ch. 26)

Fig. 26.25

: SaleFrame1

onPropertyEvent( source, name, value )

saleTextField: JTextField

setText( value.toString() )

Since this is a polymorphic operation implemented by this class, show a new interaction diagram that starts with this polymorphic version

UML notation: Note this little expression within the parameter. This is legal and consise.

Page 56: GoF Design Patterns (Ch. 26)

Fig. 26.26

«interface»PropertyListener

onPropertyEvent( source, name, value )

SaleFrame1

onPropertyEvent( source, name, value )

initialize( Sale sale )...

javax.swing.JFrame

...setTitle()setVisible()...

Sale

addPropertyListener( PropertyListener lis )publishPropertyEvent( name, value )

setTotal( Money newTotal )...

*propertyListeners

publishes events to observers/listeners/subscribers

registers them when they ask to subscribe

listens for events observes events subscribes to notification of events

Who is the observer, listener, subscriber, and publisher?

Page 57: GoF Design Patterns (Ch. 26)

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

Page 58: GoF Design Patterns (Ch. 26)

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

Page 59: GoF Design Patterns (Ch. 26)

Fig. 26.27

«interface»AlarmListener

onAlarmEvent( source, time )

Beeper

onAlarmEvent( source, time )...

{ display notification dialog box }

AlarmClock

addAlarmnListener( AlarmListener lis )publishAlarmEvent( time )

setTime( newTime )...

*alarmListeners

{ time = newTime; if ( time == alarmTime ) publishAlarmEvent( time ); }

{ alarmListeners.add( lis );}

{ for each AlarmListener al in alarmListeners al.onAlarmEvent( this, time ); }

AlarmWindow

onAlarmEvent( source, time )...

javax.swing.JFrame

...setTitle()setVisible()...

ReliabilityWatchDog

onAlarmEvent( source, time )...

{ beep }

{ check that all required processes are executing normally }