+ All Categories
Home > Documents > Chapter 26

Chapter 26

Date post: 02-Jan-2016
Category:
Upload: lawrence-oneal
View: 23 times
Download: 0 times
Share this document with a friend
Description:
Chapter 26. GoF Design Patterns. The Adapter Design Pattern. Interaction Diagram for “Adapter”. Sometimes we update domain models to reflect our more refined understanding of domain. The Factory Pattern. The Factory Pattern. Advantages: - PowerPoint PPT Presentation
39
1 Chapter 26 GoF Design Patterns
Transcript

1

Chapter 26

GoF Design Patterns

2

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

3

Interaction Diagram for “Adapter”

:Register : SAPAccountingAdapter

postSale( sale )

makePayment

the Adapter adapts to interfaces in other components

SOAP over HTTP

xxx

...

«actor»: SAPSystem

4

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

...

...

...

...

5

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;

6

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

7

The Singleton Pattern

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

factory class from everywhere?

8

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

... }}

9

The Singleton Pattern: Implementation and Design Issues

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

• Eager initialization: ???

10

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; } }

11

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?

12

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.

13

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.

14

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

15

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 )

}

16

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; }

17

Factory Creates Strategy Object on Demand

:Sale

1:PricingStrategyFactory

ps =getSalePricingStrategy

:Register

makeNewSalecreate

create(percent) ps : PercentDiscountPricingStrategy

18

The “Composite” Design Pattern

19

The “Composite” Design Pattern

20

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

21

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;}

22

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

23

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

24

Creating a Composite Strategy

:Sale

1:PricingStrategyFactory

ps =getSale

PricingStrategy

:Register

makeNewSale create

create ps :CompositeBestForCustomerPricingStrategy

create( percent ) s : PercentageDiscountPricingStrategy

add( s )

25

Creating the Pricing Strategy for a Customer (Part 1)

26

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

27

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?

28

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.

29

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

*

30

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); } //..}

31

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?

32

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

33

The Problem

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

Sale

total...

setTotal( newTotal )...

34

«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 ) ... }

35

Fig. 26.23

s : Salesf : SaleFrame1

initialize( s : Sale )

addPropertyListener( sf )

propertyListeners : List<PropertyListener>

add( sf )

36

Fig. 26.24

s :Sale

setTotal( total )

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

publishPropertyEvent( "sale.total", total )

propertylisteners[ i ] : PropertyListener

loop

37

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.

38

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

39

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 }


Recommended