chapter 26 gof design patterns. the adapter design pattern

41
Chapter 26 GoF Design Patterns

Upload: jasmin-wilcox

Post on 13-Jan-2016

247 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Chapter 26

GoF Design Patterns

Page 2: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

The Adapter Design Pattern

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 3: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Interaction Diagram for “Adapter”

:Register : SAPAccountingAdapter

postSale( sale )

makePayment

the Adapter adapts to interfaces in other components

SOAP over HTTP

xxx

...

«actor»: SAPSystem

Page 4: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Sometimes we update domain models to reflect our more refined understanding of domain

Sale

dateTime…...

SalesLineItem

quantity

Contains

1..*

1

TaxLineItem

descriptionpercentageamount

Contains

1..*

1

...

...

...

...

Page 5: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

The Factory Pattern

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 6: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

The Factory Pattern

• Advantages:– Separate the responsibility of complex object creation

into cohesive helper objects– Hide potentially complex creation logic– Allow optimizations to enhance performance

• Object caching: Create objects beforehand and keep them in memory for quick use.

• Re-cycling: Pool of connection threads in a web-server.

• ServicesFactory:– Data-driven design: Class loaded dynamically (at run

time) based on system property.– Can create other adapter classes by changing

property value

Page 7: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

The Singleton Pattern

• Issues with the factory pattern:– Who creates the factory itself?– How do we get access to the

factory class from everywhere?

Page 8: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Accessing the Singleton

:Register1

:ServicesFactory

aa = getAccountingAdapterinitialize

...

the ‘1’ indicates that visibility to this instance was achieved via the Singleton pattern

public class Register { public void initialize() { ... aa = ServicesFactory.getInstance().getAccountingAdapter();

... }}

Page 9: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

The Singleton Pattern: Implementation and Design Issues

• Lazy initialization:public static synchronized ServicesFactory getInstance() { if (instance == null) instance = new ServicesFactory(); return instance;}

• Eager initialization: ???

Page 10: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

The Singleton Pattern: Implementation and Design Issues

• Lazy initialization:public static synchronized ServicesFactory getInstance() { if (instance == null) instance = new ServicesFactory(); return instance;}

• Eager initialization:public class ServicesFactory { private static ServicesFactory instance = new ServicesFactory();

public static ServicesFactory getInstance() { return instance; } }

Page 11: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Singleton Issues

• Lazy vs. eager initialization. Which one is better?– Laziness, of course!

• Creation work (possibly holding on to expensive resources) avoided if instance never created

• Why not make all the service methods static methods of the class itself?– Why do we need an instance of the factory

object and then call its instance methods?

Page 12: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Singleton Issues

• Why not make all the service methods static methods of the class itself?– To permit subclassing: Static methods are not

polymorphic, don’t permit overriding.– Object-oriented remote communication

mechanisms (e.g. Java RMI) only work with instance methods

• Static methods are not remote-enabled.

– More flexibility: Maybe we’ll change our minds and won’t want a singleton any more.

Page 13: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Design Patterns in Interaction Diagrams

:Register accountingAdapter: SAPAccountingAdapter

postSale( sale )

makePayment

SOAP over HTTP

xxx

:Register

1:ServicesFactory

accountingAdapter = getAccountingAdapter

:Store

createcreate

: SAPAccountingAdapter

: Paymentcreate(cashTendered)

«actor»: SAPSystem

create

Page 14: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

The Strategy Pattern

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 }

• Issue: Provide more complex pricing logic.– Pricing strategy varying over time– Example: Different kinds of sales.

Page 15: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Interaction diagram for “Strategy”

: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

Context object

Page 16: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Context object has attribute visibility to its strategy

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 17: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Factory for Strategy Object

1PricingStrategyFactory

instance : PricingStrategyFactory

getInstance() : PricingStrategyFactory

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

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

Page 18: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Factory Creates Strategy Object on Demand

:Sale

1:PricingStrategyFactory

ps =getSalePricingStrategy

:Register

makeNewSalecreate

create(percent) ps : PercentDiscountPricingStrategy

Page 19: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

The “Composite” Design Pattern

Page 20: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

The “Composite” Design Pattern

Page 21: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

The “Composite” Design Pattern

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 22: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

public abstract class CompositePricingStrategy implements ISalePricingStrategy {

protected List strategies = new ArrayList();

public add (ISalePricingStrategy s) { strategies.add(s); }

public abstract Money getTotal( Sale sale );}

public class ComputeBestForCustomerPricingStrategy extends CompositePricingStrategy {

Money lowestTotal = new Money( Integer.MAX_VALUE );

for (Iterator i = strategies.iterator(); i.hasNext(); ) { ISalePricingStrategy strategy = (ISalePricingStrategy) i.next(); Money total = strategy.getTotal( sale ); lowestTotal = total.min( lowestTotal); } return lowestTotal;}

Page 23: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Collaboration with a Composite

:CompositeBestForCustomerPricingStrategy

s : Sale

st = getSubtotal

t = getTotal

lineItems[ i ] :SalesLineItem

t = getTotal( s )

the Sale object treats a Composite Strategy that contains other strategies just like any other ISalePricingStrategy

x = getTotal( s )

strategies[ j ] :: ISalePricingStrategy

UML: ISalePricingStrategy is an interface, not a class; this is the way in UML 2 to indicate an object of an unknown class, but that implements this interface

{ t = min(set of all x) }

loop

loop

Page 24: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Abstract Classes and Methods in the UML

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 25: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Creating a Composite Strategy

:Sale

1:PricingStrategyFactory

ps =getSale

PricingStrategy

:Register

makeNewSale create

create ps :CompositeBestForCustomerPricingStrategy

create( percent ) s : PercentageDiscountPricingStrategy

add( s )

Page 26: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Creating the Pricing Strategy for a Customer (Part 1)

Page 27: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Creating the Pricing Strategy for a Customer (Part 2)

s :Sale

1:PricingStrategy

Factory

addCustomerPricingStrategy( s )

ps :CompositeBestForCustomerPricingStrategy

create( pct ) s : PercentageDiscountPricingStrategy

add( s )

by Expert

enterCustomerForDiscount( c : Customer )

c = getCustomer

by Factory and High Cohesion

by Expert ps = getPricingStrategy

pct = getCustomer

Percentage( c )

by High Cohesion

by Factory and Composite

Pass Aggregate Object as Parameter

sd Enter Customer For Discount

Page 28: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Creating the Pricing Strategy for a Customer (Part 2)

s :Sale

1:PricingStrategy

Factory

addCustomerPricingStrategy( s )

ps :CompositeBestForCustomerPricingStrategy

create( pct ) s : PercentageDiscountPricingStrategy

add( s )

by Expert

enterCustomerForDiscount( c : Customer )

c = getCustomer

by Factory and High Cohesion

by Expert ps = getPricingStrategy

pct = getCustomer

Percentage( c )

by High Cohesion

by Factory and Composite

Pass Aggregate Object as Parameter

sd Enter Customer For Discount

WHY?

Page 29: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

The “Façade” Design Pattern

• Additional requirement in new iteration of POS: Pluggable business rules

• Example– New sale might be paid by gift certificate.

Only one item can be purchased by a gift certificate– If sale paid by gift certificate, invalidate all payments

with the type of “change due back to customer” different from gift certificate.

– Some sales might be charitable donations by the store. Limited to less than $250 each. Manager must be logged in as cashier for this transaction.

• One of the concerns: What happens to enterItem?

Page 30: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

enterItem and Low Impact of Change

• Suppose architect wants low impact of change in pluggable business rules.

• Suppose also that the architect is not sure how to implement the pluggable business rules.– Wants to experiment with different ways of implementing them.

• Solution: The “Façade” design pattern– Problem: Need a common, unified interface to a disparate set of

implementations or interfaces– Solution: Define a single point of contact to the subsystem

containing the implementations• This façade object has a unified interface• Internal implementation details hidden

– Example: The use-case controller objects in your project.

Page 31: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

The “Façade” Design Pattern

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 32: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Façade code example

public class Sale {

public void makeLineItem( ProductDescription desc, int quantity) {SalesLineItem sli = new SalesLineItem( desc, quantity);

// call to the Façade. Notice Singleton pattern if (POSRuleEngineFacede.getInstance().isInvalid(sli,this) )

return; lineItems.add(sli); } //..}

Page 33: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Observer/Publish-Subscribe/Delegation Event Model

• Another requirement: GUI window refreshes its display of the sales total when the total changes– Later: GUI updates display when other data

changes as well

• What’s wrong with the following?– When the Sale object changes its total, it

sends a message to a window, asking it to refresh the display?

Page 34: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Publish-Subscribe Pattern

• What’s wrong with the following?– When the Sale object changes its total, it

sends a message to a window, asking it to refresh the display?

• Answer: The Model-View Separation principle discourages such solutions– Model objects (objects in the domain) should

not know of UI objects– If UI changes, model objects should not need

to change

Page 35: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

The Problem

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

Sale

total...

setTotal( newTotal )...

Page 36: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

«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 37: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Fig. 26.23

s : Salesf : SaleFrame1

initialize( s : Sale )

addPropertyListener( sf )

propertyListeners : List<PropertyListener>

add( sf )

Page 38: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

Fig. 26.24

s :Sale

setTotal( total )

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

publishPropertyEvent( "sale.total", total )

propertylisteners[ i ] : PropertyListener

loop

Page 39: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

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 40: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

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

Page 41: Chapter 26 GoF Design Patterns. The Adapter Design Pattern

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 }