Professional Documents
Culture Documents
Pattern-Oriented Design
by Rick Mercer based on the GoF book and
Design Patterns Explained
A New Perspective on Object-Oriented Design
Alan Shalloway, James R. Trott
Addison Wesley ISBN 0-201-71594-5
1
Using Patterns to Design
4
What is variable in the design?
7
Assign Responsibilities
SalesOrder responsibilities:
Allow users to make an order using GUI input
Process the order
Print a sales receipt
TaskController SalesOrder
SalesTicketPrinter
+calcTax():double
8
Changing Requirements
TaskController SalesOrder
SalesTicketPrinter
+calcTax():double
US Tax
Rules
Canadian
Tax Rules
CanadianSalesOrder
+calcTax():double
10
Favor Composition Over
Inheritance
Design pattern theme of composition over
inheritance is ignored in previous design
Here is a different approach
consider what is variable in the design
encapsulate the concept the varies
Accept the fact that tax rules vary country to
country and state to state and county to county, and
sometimes city to city (like in Arizona) and they
change
11
Alternate Designs
SalesTick etPrinte r
+calcTax():double
f or each Salable
reult += taxAmount(s,q)
interf ace
Ta xCal cul ator
+taxAmount(itemSold:Salable,quantity:double):double
USTaxer CandianTaxe r
+taxAmount(itemSold:Salable,quantity:double):double+taxAmount(itemSold:Salable,quantity:double)
13
Why does Strategy make this
design better?
Better Cohesion (hangs together)
sales tax details are in its own class
Easy to add tax rules from different countries
Easier to shift responsibilities
In the first design where CanadianSalesOrder extends
USSalesOrder, only TaskController is able to
determine which type of sales order to use
With Strategy, either TaskController or SalesOrder
could set the TaxCalculator
14
Determine What Varies
What Varies?
The business rules for taxation
Current design handles variations at least as well as
the other design design
Current design will handle future variations as well
A family of tax calculation algorithms have been
encapsulated as objects, they are interchangeable,
Strategy pattern applied in an Ecommerce system
15
Using the Strategy Pattern
20
USTaxer is now a Singleton
private USTaxer() {
taxRate = 0.06; // greatly simplified
}
1 1..*
composition Salable
1
interface -cost:double
Ta xCalculator
+price():double
+taxAmount(itemSold:Salab le,quantity:double):double
implements
USTaxer CanadianTaxe r
-instance:USTaxer -instance:CanadianTaxer
-taxRate:double -taxRate:double
22
I have an instance of myself I have an instance of myse
Aggregation vs. Composition
24
Decorate SalesTicketPrinter
He ader Foote r
prints
Configuration +printTicket():void
+getSalesTicket():Component
1
Ti cketDecorator SalesTick et
ller
-myComponent:Component
+printTicket():void
+TicketDecorator()
+main(args:String[]):void
+TicketDecorator(c:Component)
+printTicket():void
+FooterDecorator2(c:Component)
+HeaderDecorator1(c:Component)+HeaderDecorator2(c:Component)
+FooterDecorator1(c:Com
+printTicket():void +printTicket():void +printTicket():void +printTicket():void
+printFooter():v oid +printHeader():void +printHeader():void +printFooter():v oid
le):double
29
A Simple SalesTicket
public TicketDecorator() {
myComponent = null;
}
public TicketDecorator(Component c) {
myComponent = c;
}
@Override
public void printTicket() {
if (myComponent != null)
myComponent.printTicket();
}
} 31
A Header Decorator
@Override
public void printTicket() {
this.printHeader();
super.printTicket();
}
32
A Footer Decorator
@Override
public void printTicket() {
super.printTicket();
this.printFooter();
}
34
Simple Configuration
// This method determines how to decorate SalesTicket
class Configuration {
Output:
@@ Header One @@
>> Header Two <<
Customer: Bob
The sales ticket itself
Total: $123.45
%% FOOTER one %%
## FOOTER two ##
36
SalesOrder
SalesOrder
delegates to
+main(args:String[]):void
+printTicket():void Component to
The system +calcTax():double
print ticket
on 2 slides 1 1
1..*
1
Salable
interf ace Tas kController
-cost:double Ta xCal cul ator
+price():double
+taxAmount(itemSold:Salable,quantity:double):double
-instance:CanadianTaxer -instance:USTaxer
-taxRate:double -taxRate:double
+FooterDecorator2(c:Co
+printTicket():void
-CanadianTaxer() -USTax er()
+printFooter():v oid
+getInstance():CanadianTaxer +getInstance():USTaxer
+taxAmount(item:Salable,quant:double):double
+taxAmount(item:Salable,quant:double):double
+main(args:String[]):void
I have an instance of myself
37
I have an instance of myself
Component
prints
Configuration +printTicket():void
+getSalesTicket():Component
1
Ti cketDecorator SalesTick et
-myComponent:Component
+printTicket():void
+TicketDecorator()
+main(args:String[]):void
+TicketDecorator(c:Component)
+printTicket():void
terDecorator2(c:Component)
+HeaderDecorator1(c:Component)+HeaderDecorator2(c:Component)
+FooterDecorator1(c:Component)
tTicket():void +printTicket():void +printTicket():void +printTicket():void
tFooter():v oid +printHeader():void +printHeader():void +printFooter():v oid
e
38
elf
CanadianTaxe r
-CanadianTaxer()
+getInstance():CanadianTaxer
New Requirements: Send an email to a new +taxAmount(item:Salable,quan
+addCustomer():void
Welcom eEMail
+doWelcomLetter():void
39
Or Use Observer
40
Observer
41
-instance:CanadianTaxer -instance:USTa
-taxRate:double -taxRate:doubl
java.util.Observer
Address Verification
+addCustomer():void
java.util.Observer
Welcom eEMail
+doWelcomeLetter():void
+update(o:java.util.Observable,arg:Object):v oid
42