OOP2024Java Exercise DesignPatterns Strategy Lap10
OOP2024Java Exercise DesignPatterns Strategy Lap10
Strategy Pattern
Contents
1 Intent 2
2 Problem 2
3 Solution 3
4 Structure 4
5 Pseudocode 5
6 Applicability 6
7 How to Implement 7
8 Real-World Analogy 7
11 Exercises 9
1
HaQT Object-Oriented Programming
1 Intent
Strategy is a behavioral design pattern that lets you define a family of algorithms, put each
of them into a separate class, and make their objects interchangeable.
2 Problem
One day you decided to create a navigation app for casual travelers. The app was centered
around a beautiful map which helped users quickly orient themselves in any city.
One of the most requested features for the app was automatic route planning. A user should
be able to enter an address and see the fastest route to that destination displayed on the
map.
The first version of the app could only build the routes over roads. People who traveled by
car were bursting with joy. But apparently, not everybody likes to drive on their vacation.
So with the next update, you added an option to build walking routes. Right after that, you
added another option to let people use public transport in their routes.
However, that was only the beginning. Later you planned to add route building for cyclists.
And even later, another option for building routes through all of a city’s tourist attractions.
2
HaQT Object-Oriented Programming
While from a business perspective the app was a success, the technical part caused you many
headaches. Each time you added a new routing algorithm, the main class of the navigator
doubled in size. At some point, the beast became too hard to maintain.
Any change to one of the algorithms, whether it was a simple bug fix or a slight adjustment
of the street score, affected the whole class, increasing the chance of creating an error in
already-working code.
In addition, teamwork became inefficient. Your teammates, who had been hired right after
the successful release, complain that they spend too much time resolving merge conflicts.
Implementing a new feature requires you to change the same huge class, conflicting with the
code produced by other people.
3 Solution
The Strategy pattern suggests that you take a class that does something specific in a lot of
different ways and extract all of these algorithms into separate classes called strategies.
The original class, called context, must have a field for storing a reference to one of the
strategies. The context delegates the work to a linked strategy object instead of executing
it on its own.
The context isn’t responsible for selecting an appropriate algorithm for the job. Instead,
the client passes the desired strategy to the context. In fact, the context doesn’t know
much about strategies. It works with all strategies through the same generic interface, which
only exposes a single method for triggering the algorithm encapsulated within the selected
strategy.
This way the context becomes independent of concrete strategies, so you can add new algo-
rithms or modify existing ones without changing the code of the context or other strategies.
3
HaQT Object-Oriented Programming
In our navigation app, each routing algorithm can be extracted to its own class with a single
buildRoute method. The method accepts an origin and destination and returns a collection
of the route’s checkpoints.
Even though given the same arguments, each routing class might build a different route, the
main navigator class doesn’t really care which algorithm is selected since its primary job is
to render a set of checkpoints on the map. The class has a method for switching the active
routing strategy, so its clients, such as the buttons in the user interface, can replace the
currently selected routing behavior with another one.
4 Structure
Structure of strategy.
1. The Context maintains a reference to one of the concrete strategies and communicates
with this object only via the strategy interface.
2. The Strategy interface is common to all concrete strategies. It declares a method the
context uses to execute a strategy.
4. The context calls the execution method on the linked strategy object each time it needs
to run the algorithm. The context doesn’t know what type of strategy it works with
or how the algorithm is executed.
5. The Client creates a specific strategy object and passes it to the context. The context
exposes a setter which lets clients replace the strategy associated with the context at
runtime.
4
HaQT Object-Oriented Programming
5 Pseudocode
In this example, the context uses multiple strategies to execute various arithmetic operations.
1 // The s t r a t e g y i n t e r f a c e d e c l a r e s o p e r a t i o n s common t o a l l s u p p o r t e d
// v e r s i o n s o f some a l g o r i t h m . The c o n t e x t u s e s t h i s i n t e r f a c e t o c a l l
3 // t h e a l g o r i t h m d e f i n e d by t h e c o n c r e t e s t r a t e g i e s .
i n t e r f a c e Strategy i s
5 method e x e c u t e ( a , b )
7
// C o n c r e t e s t r a t e g i e s implement t h e a l g o r i t h m w h i l e f o l l o w i n g t h e b a s e
9 // s t r a t e g y i n t e r f a c e . The i n t e r f a c e makes them i n t e r c h a n g e a b l e i n
// t h e c o n t e x t .
11 c l a s s ConcreteStrategyAdd implements S t r a t e g y i s
method e x e c u t e ( a , b ) i s
13 return a + b
15
c l a s s C o n c r e t e S t r a t e g y S u b t r a c t implements S t r a t e g y i s
17 method e x e c u t e ( a , b ) i s
return a − b
19
21 c l a s s C o n c r e t e S t r a t e g y M u l t i p l y implements S t r a t e g y i s
method e x e c u t e ( a , b ) i s
23 return a ∗ b
25
// The c o n t e x t d e f i n e s t h e i n t e r f a c e o f i n t e r e s t t o c l i e n t s .
27 c l a s s Context i s
// The c o n t e x t m a i n t a i n s a r e f e r e n c e t o one o f t h e s t r a t e g y o b j e c t s .
29 // The c o n t e x t doesn ’ t know t h e c o n c r e t e c l a s s o f a s t r a t e g y .
// I t s h o u l d work with a l l s t r a t e g i e s v i a t h e s t r a t e g y i n t e r f a c e .
31 private strategy : Strategy
33 // U s u a l l y t h e c o n t e x t a c c e p t s a s t r a t e g y through t h e c o n s t r u c t o r ,
// and a l s o p r o v i d e s a s e t t e r s o t h a t t h e s t r a t e g y can be s w i t c h e d
35 // a t runtime .
method s e t S t r a t e g y ( S t r a t e g y s t r a t e g y ) i s
37 this . strategy = strategy
5
HaQT Object-Oriented Programming
c l a s s E xa m pl eAp pl ic a tio n i s
49 method main ( ) i s
Create context o b j e c t .
51
Read f i r s t number .
53 Read l a s t number .
Read t h e d e s i r e d a c t i o n from u s e r i n p u t .
55
i f ( a c t i o n = = a d d i t i o n ) then
57 c o n t e x t . s e t S t r a t e g y ( new ConcreteStrategyAdd ( ) )
59 i f ( a c t i o n = = s u b t r a c t i o n ) then
c o n t e x t . s e t S t r a t e g y ( new C o n c r e t e S t r a t e g y S u b t r a c t ( ) )
61
i f ( a c t i o n = = m u l t i p l i c a t i o n ) then
63 c o n t e x t . s e t S t r a t e g y ( new C o n c r e t e S t r a t e g y M u l t i p l y ( ) )
67 Print r e s u l t .
6 Applicability
• Use the Strategy pattern when you want to use different variants of an algorithm within
an object and be able to switch from one algorithm to another during runtime.
▷ The Strategy pattern lets you indirectly alter the object’s behavior at runtime by
associating it with different sub-objects which can perform specific sub-tasks in different
ways.
• Use the Strategy when you have a lot of similar classes that only differ in the way they
execute some behavior.
▷ The Strategy pattern lets you extract the varying behavior into a separate class hier-
archy and combine the original classes into one, thereby reducing duplicate code.
• Use the pattern to isolate the business logic of a class from the implementation details
of algorithms that may not be as important in the context of that logic.
▷ The Strategy pattern lets you isolate the code, internal data, and dependencies of
various algorithms from the rest of the code. Various clients get a simple interface to
execute the algorithms and switch them at runtime.
• Use the pattern when your class has a massive conditional statement that switches
between different variants of the same algorithm.
▷ The Strategy pattern lets you do away with such a conditional by extracting all algo-
rithms into separate classes, all of which implement the same interface. The original
6
HaQT Object-Oriented Programming
object delegates execution to one of these objects, instead of implementing all variants
of the algorithm.
7 How to Implement
1. In the context class, identify an algorithm that’s prone to frequent changes. It may
also be a massive conditional that selects and executes a variant of the same algorithm
at runtime.
3. One by one, extract all algorithms into their own classes. They should all implement
the strategy interface.
4. In the context class, add a field for storing a reference to a strategy object. Provide
a setter for replacing values of that field. The context should work with the strategy
object only via the strategy interface. The context may define an interface which lets
the strategy access its data.
5. Clients of the context must associate it with a suitable strategy that matches the way
they expect the context to perform its primary job.
8 Real-World Analogy
Imagine that you have to get to the airport. You can catch a bus, order a cab, or get on
your bicycle. These are your transportation strategies. You can pick one of the strategies
depending on factors such as budget or time constraints.
7
HaQT Object-Oriented Programming
8
HaQT Object-Oriented Programming
11 Exercises
In this example, the program implement the various payment methods in an e-commerce
application. After selecting a product to purchase, a customer picks a payment method:
either Paypal or Credit Card.
1 package com . p a t t e r n s . s t r a t e g i e s ;
3 /∗ ∗
∗ Common i n t e r f a c e f o r a l l s t r a t e g i e s .
5 ∗/
p u b l i c i n t e r f a c e P aySt ra tegy {
7 b o o l e a n pay ( i n t paymentAmount ) ;
void collectPaymentDetails ( ) ;
9 }
1 package com . p a t t e r n s . s t r a t e g y . s t r a t e g i e s ;
9 /∗ ∗
∗ C o n c r e t e s t r a t e g y . Implements Paypal payment method .
11 ∗/
p u b l i c c l a s s PayByPaypal implements Pa yS tr at eg y {
13 p r i v a t e s t a t i c f i n a l Map<S t r i n g , S t r i n g > DATA_BASE = new HashMap<>() ;
p r i v a t e f i n a l B u f f e r e d R e a d e r READER
15 = new B u f f e r e d R e a d e r ( new InputStreamReader ( System . i n ) ) ;
private String email ;
17 p r i v a t e S t r i n g password ;
private boolean signedIn ;
19
static {
21 DATA_BASE. put ( " amanda1985 " , "amanda@ya . com" ) ;
DATA_BASE. put ( " qwerty " , "john@amazon . eu " ) ;
23 }
9
HaQT Object-Oriented Programming
25 /∗ ∗
∗ C o l l e c t customer ’ s data .
27 ∗/
@Override
29 public void collectPaymentDetails ( ) {
try {
31 while ( ! signedIn ) {
System . out . p r i n t ( " Enter t h e u s e r ’ s e m a i l : " ) ;
33 e m a i l = READER. r e a d L i n e ( ) ;
System . out . p r i n t ( " Enter t h e password : " ) ;
35 password = READER. r e a d L i n e ( ) ;
i f ( verify () ) {
37 System . out . p r i n t l n ( " Data v e r i f i c a t i o n has been s u c c e s s f u l . " ) ;
} else {
39 System . out . p r i n t l n ( "Wrong e m a i l o r password ! " ) ;
}
41 }
} c a t c h ( IOException ex ) {
43 ex . p r i n t S t a c k T r a c e ( ) ;
}
45 }
47 private boolean v e r i f y ( ) {
s e t S i g n e d I n ( e m a i l . e q u a l s (DATA_BASE. g e t ( password ) ) ) ;
49 return signedIn ;
}
51
/∗ ∗
53 ∗ Save customer data f o r f u t u r e s h o p p i n g a t t e m p t s .
∗/
55 @Override
p u b l i c b o o l e a n pay ( i n t paymentAmount ) {
57 i f ( signedIn ) {
System . out . p r i n t l n ( " Paying " + paymentAmount + " u s i n g Paypal . " ) ;
59 return true ;
}
61 return f a l s e ;
}
63
pri vate void setSignedIn ( boolean signedIn ) {
65 this . signedIn = signedIn ;
}
67 }
1 package com . p a t t e r n s . s t r a t e g y . s t r a t e g i e s ;
3 import j a v a . i o . B u f f e r e d R e a d e r ;
10
HaQT Object-Oriented Programming
import j a v a . i o . IOException ;
5 import j a v a . i o . InputStreamReader ;
7 /∗ ∗
∗ C o n c r et e s t r a t e g y . Implements c r e d i t c a r d payment method .
9 ∗/
p u b l i c c l a s s PayByCreditCard implements P a yS tr at eg y {
11 p r i v a t e f i n a l B u f f e r e d R e a d e r READER
= new B u f f e r e d R e a d e r ( new InputStreamReader ( System . i n ) ) ;
13 p r i v a t e CreditCard c a r d ;
15 /∗ ∗
∗ C o l l e c t c r e d i t c a r d data .
17 ∗/
@Override
19 public void collectPaymentDetails ( ) {
try {
21 System . out . p r i n t ( " Enter t h e c a r d number : " ) ;
S t r i n g number = READER. r e a d L i n e ( ) ;
23 System . out . p r i n t ( " Enter t h e c a r d e x p i r a t i o n d a t e ’mm/yy ’ : " ) ;
S t r i n g d a t e = READER. r e a d L i n e ( ) ;
25 System . out . p r i n t ( " Enter t h e Card V e r i f i c a t i o n Value code : " ) ;
S t r i n g c a r d V e r i f i c a t i o n V a l u e = READER. r e a d L i n e ( ) ;
27
i f ( C r e d i t C a r d V a l i d a t o r . i s V a l i d ( number ) ) {
29 c a r d = new CreditCard ( number , date , c a r d V e r i f i c a t i o n V a l u e ) ;
}
31 } c a t c h ( IOException ex ) {
ex . p r i n t S t a c k T r a c e ( ) ;
33 }
}
35
/∗ ∗
37 ∗ A f t e r c a r d v a l i d a t i o n we can c h a r g e customer ’ s c r e d i t c a r d .
∗/
39 @Override
p u b l i c b o o l e a n pay ( i n t paymentAmount ) {
41 i f ( cardIsPresent () ) {
System . out . p r i n t l n ( " Paying " + paymentAmount + " using Credit Card." ) ;
43 c a r d . setAmount ( c a r d . getAmount ( ) − paymentAmount ) ;
return true ;
45 }
return f a l s e ;
47 }
11
HaQT Object-Oriented Programming
package com . p a t t e r n s . s t r a t e g y . s t r a t e g i e s ;
2
/∗ ∗
4 ∗ Dummy c r e d i t c a r d c l a s s .
∗/
6 p u b l i c c l a s s CreditCard {
p r i v a t e i n t amount ;
8 p r i v a t e S t r i n g number ;
p r i v a t e S t r i n g date ;
10 private String cardVerificationValue ;
p u b l i c v o i d setAmount ( i n t amount ) {
20 t h i s . amount = amount ;
}
22
p u b l i c i n t getAmount ( ) {
24 r e t u r n amount ;
}
26
p u l i c S t r i n g getNumber ( ) {
28 r e t u r n t h i s . number ;
}
30 }
/∗ ∗
2 ∗ Java program to check if a given credit card is valid or not, using Luhn algorithm.
∗/
4 public c l a s s CreditCardValidator {
// Return t r u e i f t h e c a r d number i s v a l i d
6 p u b l i c s t a t i c b o o l e a n i s V a l i d ( l o n g number ) {
r e t u r n ( g e t S i z e ( number ) >= 13
8 && g e t S i z e ( number ) <= 1 6 )
&& ( p r e f i x M a t c h e d ( number , 4 )
10 | | p r e f i x M a t c h e d ( number , 5 )
| | p r e f i x M a t c h e d ( number , 3 7 )
12 | | p r e f i x M a t c h e d ( number , 6 ) )
&& ( ( sumOfDoubleEvenPlace ( number )
14 + sumOfOddPlace ( number ) ) % 10 = = 0 ) ;
}
16
p u b l i c s t a t i c b o o l e a n i s V a l i d ( S t r i n g number ) {
12
HaQT Object-Oriented Programming
50 // Return t r u e i f t h e d i g i t d i s a p r e f i x f o r number
p r i v a t e s t a t i c b o o l e a n p r e f i x M a t c h e d ( l o n g number , i n t d ) {
52 r e t u r n g e t P r e f i x ( number , g e t S i z e ( d ) ) = = d ;
}
54
// Return t h e number o f d i g i t s i n d
56 private s t a t i c int getSize ( long d) {
S t r i n g num = d + " " ;
58 r e t u r n num . l e n g t h ( ) ;
}
60
// Return t h e f i r s t k number o f d i g i t s from number .
62 // I f t h e number o f d i g i t s i n number i s l e s s than k , r e t u r n number .
p r i v a t e s t a t i c l o n g g e t P r e f i x ( l o n g number , i n t k ) {
64 i f ( g e t S i z e ( number ) > k ) {
S t r i n g num = number + " " ;
66 r e t u r n Long . parseLong (num . s u b s t r i n g ( 0 , k ) ) ;
}
68 r e t u r n number ;
}
13
HaQT Object-Oriented Programming
70 }
package com . p a t t e r n s . s t r a t e g y . o r d e r ;
2
import com . p a t t e r n s . s t r a t e g y . s t r a t e g i e s . P ay St ra te gy ;
4
/∗ ∗
6 ∗ Order class. Doesn’t know the concrete payment method (strategy) user has picked.
∗ It uses common strategy interface to delegate collecting payment data to strategy object.
8 ∗ It can be used to save order to database.
∗/
10 p u b l i c c l a s s Order {
private int totalCost = 0;
12 private boolean isClosed = f a l s e ;
14 p u b l i c v o i d p r o c e s s O r d e r U s i n g P a y p a l ( PayByPaypal paypal ) {
paypal . c o l l e c t P a y m e n t D e t a i l s ( ) ;
16 }
18 p u b l i c v o i d p r o c e s s O r d e r U s i n g C r e d i t C a r d ( PayByCreditCard c r e d i t C a r d ) {
creditCard . collectPaymentDetails () ;
20 }
1 package com . p a t t e r n s . s t r a t e g y . s t r a t e g i e s ;
14
HaQT Object-Oriented Programming
import com . p a t t e r n s . s t r a t e g y . s t r a t e g i e s . P ay St ra te gy ;
7
import java . i o . BufferedReader ;
9 import java . i o . IOException ;
import java . i o . InputStreamReader ;
11 import java . u t i l . HashMap ;
import java . u t i l . Map ;
13
/∗ ∗
15 ∗ World f i r s t c o n s o l e e−commerce a p p l i c a t i o n .
∗/
17 p u b l i c c l a s s App {
p r i v a t e s t a t i c Map<I n t e g e r , I n t e g e r > p r i c e O n P r o d u c t s = new HashMap<>() ;
19 pri vate s t a t i c BufferedReader reader
= new B u f f e r e d R e a d e r ( new InputStreamReader ( System . i n ) ) ;
21 p r i v a t e s t a t i c Order o r d e r = new Order ( ) ;
p r i v a t e s t a t i c PaySt ra tegy s t r a t e g y ;
23
static {
25 p r i c e O n P r o d u c t s . put ( 1 , 2200) ;
p r i c e O n P r o d u c t s . put ( 2 , 1850) ;
27 p r i c e O n P r o d u c t s . put ( 3 , 1100) ;
p r i c e O n P r o d u c t s . put ( 4 , 890) ;
29 }
35 String continueChoice ;
do {
37 System . out . p r i n t ( " P l e a s e , s e l e c t a p r o d u c t : " + " \n" +
" 1 − Mother board " + " \n" +
39 " 2 − CPU" + " \n" +
" 3 − HDD" + " \n" +
41 " 4 − Memory" + " \n" ) ;
in t choice = Integer . parseInt ( reader . readLine () ) ;
43 c o s t = priceOnProducts . get ( c h o i c e ) ;
System . out . p r i n t ( "Count : " ) ;
45 i n t count = I n t e g e r . p a r s e I n t ( r e a d e r . r e a d L i n e ( ) ) ;
o r d e r . s e t T o t a l C o s t ( c o s t ∗ count ) ;
47 System . out . p r i n t ( "Do you wish to continue selecting products? Y/N: " ) ;
continueChoice = reader . readLine () ;
49 } w h i l e ( c o n t i n u e C h o i c e . e q u a l s I g n o r e C a s e ( "Y" ) ) ;
51 i f ( strategy == null ) {
System . out . p r i n t l n ( " P l e a s e , s e l e c t a payment method : " + " \n"
53 + " 1 − PalPay " + " \n"
+ " 2 − C r e d i t Card" ) ;
55 S t r i n g paymentMethod = r e a d e r . r e a d L i n e ( ) ;
57 // C l i e n t c r e a t e s d i f f e r e n t s t r a t e g i e s based on i n p u t from u s e r ,
15
HaQT Object-Oriented Programming
// a p p l i c a t i o n c o n f i g u r a t i o n , e t c .
59 i f ( paymentMethod . e q u a l s ( " 1 " ) ) {
s t r a t e g y = new PayByPaypal ( ) ;
61 o r d e r . processOrderByPaypal ( s t r a t e g y ) ;
} else {
63 s t r a t e g y = new PayByCreditCard ( ) ;
order . processOrderByCreditCard ( s t r a t e g y ) ;
65 }
}
67
1. Refactoring the above program using Strategy Pattern and Singleton Pattern.
3. Write a program that allows the selection of using BubbleSort, SelectionSort, Inser-
tionSort algorithms at run-time to sort an array of integers.
4. Take an example of Strategy Pattern and write code to demostrate the program.
16