Strategy Design Pattern in Java

Introduction

The strategy pattern is a behavioral design pattern that enables an algorithm’s behavior to be selected at runtime without causing tight coupling. The strategy pattern defines a family of algorithms, encapsulates each algorithm, and makes algorithms interchangeable. Strategy pattern lets the algorithm vary independently from clients that use it.

So you define a strategy wherein a particular algorithm or implementation is applicable at runtime based on your requirement.

The definition in original Gang of Four book is given below

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

Class Diagram

Strategy Pattern in Java

Example Scenario

Let’s say you are implementing a shopping cart where you need to provide payment methods that users will use to pay after purchasing goods. Therefore you need to provide a payment method at runtime whether a user wants to pay through debit/credit card or paypal or net banking or cash on delivery. You also need to calculate the final payable amount when user choose one of the payment methods. Because you may give discount based on payment method. For example, payment using Credit Card will get 3% discount, using Debit Card will get 1.5% discount, using PayPal user has to pay 4.5% extra charge on the final bill amount, etc.

Another example could be, you can have slightly different temperature at different time (morning, noon, afternoon, evening, etc.) in a day. So you do not know what would be the temperature at different time, until you reach to a particular time of the day, for example, morning, evening, etc. Therefore the actual temperature can be determined at runtime or a particular time of the day. So this is the whole point of Strategy pattern.

Implementation

I will implement first example and later I will see the different temperatures at different times of the day.

I will create an interface Payment and various client classes will implement its own logic to calculate final payable amount for a goods.

package com.roytuts.java.strategy.design.pattern.payment;

public interface Payment {

	void pay(double amount);

}

Using Credit Card payment, let’s say you want to give 3% discount on the final bill amount. So you can implement the pay() method as given below:

package com.roytuts.java.strategy.design.pattern.payment;

public class CreditCardPayment implements Payment {

	@Override
	public void pay(double amount) {
		amount -= amount * 3 / 100;// 3% discount
		System.out.println("Payable amount using Credit Card: Rs. " + amount);
	}

}

Using Debit Card payment, you may give 1.5% discount on the final bill amount.

package com.roytuts.java.strategy.design.pattern.payment;

public class DebitCardPayment implements Payment {

	@Override
	public void pay(double amount) {
		amount -= amount * 1.5 / 100;// discount 1.5 percent
		System.out.println("Payable amount using Debit Card: Rs. " + amount);
	}

}

Using PayPal payment, user has to pay extra 4.5% charge for the PayPal system.

package com.roytuts.java.strategy.design.pattern.payment;

public class PayPalPayment implements Payment {

	@Override
	public void pay(double amount) {
		amount += amount * 4.5 / 100;// PayPal charge
		System.out.println("Payable amount using Debit Card: Rs. " + amount);
	}

}

The payment strategy will determine which payment method is being used at runtime and will decide the final amount after calculating discount or charge.

package com.roytuts.java.strategy.design.pattern.payment;

public class PaymentStrategy {

	private Payment payment;

	public PaymentStrategy(Payment payment) {
		this.payment = payment;
	}

	public Payment getPayment() {
		return payment;
	}

	public void payAmount(double amount) {
		payment.pay(amount);
	}

}

Main class – a class having a main method – is used to test the strategy pattern.

package com.roytuts.java.strategy.design.pattern.payment;

public class StrategyPatternTest {

	public static void main(String[] args) {
		double price = 34560;// goods price in Rs

		Payment debitCardPayment = new DebitCardPayment();
		Payment creditCardPayment = new CreditCardPayment();
		Payment payPalPayment = new PayPalPayment();

		PaymentStrategy paymentStrategy = new PaymentStrategy(debitCardPayment);
		paymentStrategy.payAmount(price);

		paymentStrategy = new PaymentStrategy(creditCardPayment);
		paymentStrategy.payAmount(price);

		paymentStrategy = new PaymentStrategy(payPalPayment);
		paymentStrategy.payAmount(price);
	}

}

By executing the above main class you will get the following output:

Payable amount using Debit Card: Rs. 34041.6
Payable amount using Credit Card: Rs. 33523.2
Payable amount using Debit Card: Rs. 36115.2

Now let’s implement the second example I had given earlier in Example section.

Define a interface DayTemperature, which has one method displayTemperature(). The client classes will provide different temperatures at different times of the day.

package com.roytuts.java.strategy.design.pattern.temperature;

public interface DayTemperature {

	void displayTemperature(String temp);

}

Now I will create below classes that implement the above interface to provide the temperature at different times of the day.

The below class shows temperature for morning.

package com.roytuts.java.strategy.design.pattern.temperature;

public class MorningTemperature implements DayTemperature {

	@Override
	public void displayTemperature(String temp) {
		System.out.println("Today's temperature at morning : " + temp);
	}

}

The below class shows temperature for noon.

package com.roytuts.java.strategy.design.pattern.temperature;

public class NoonTemperature implements DayTemperature {

	@Override
	public void displayTemperature(String temp) {
		System.out.println("Today's temperature at noon : " + temp);
	}

}

The below class display temperature for afternoon.

package com.roytuts.java.strategy.design.pattern.temperature;

public class AfterNoonTemperature implements DayTemperature {

	@Override
	public void displayTemperature(String temp) {
		System.out.println("Today's temperature at afternoon : " + temp);
	}

}

The below class displays temperature for evening.

package com.roytuts.java.strategy.design.pattern.temperature;

public class EveningTemperature implements DayTemperature {

	@Override
	public void displayTemperature(String temp) {
		System.out.println("Today's temperature at evening : " + temp);
	}

}

The below class displays temperature for night.

package com.roytuts.java.strategy.design.pattern.temperature;

public class NightTemperature implements DayTemperature {

	@Override
	public void displayTemperature(String temp) {
		System.out.println("Today's temperature at night : " + temp);
	}

}

Define a day time strategy to determine the temperature at a particular time of the day. This is the strategy that uses the appropriate temperature client class at runtime to show the temperature.

package com.roytuts.java.strategy.design.pattern.temperature;

public class DayTimeTemperature {

	private DayTemperature strategy;

	public DayTimeTemperature(DayTemperature strategy) {
		this.strategy = strategy;
	}

	public DayTemperature getStrategy() {
		return strategy;
	}

	public void setStrategy(DayTemperature strategy) {
		this.strategy = strategy;
	}

	public void showTemperature(String temp) {
		strategy.displayTemperature(temp);
	}

}

Create below main class to test strategy design pattern.

package com.roytuts.java.strategy.design.pattern.temperature;

public class StrategyPatternTest {

	public static void main(String[] args) {
		DayTemperature morningTemp = new MorningTemperature();
		DayTemperature noonTemp = new NoonTemperature();
		DayTemperature afterNoonTemp = new AfterNoonTemperature();
		DayTemperature eveningTemp = new EveningTemperature();
		DayTemperature nightTemp = new NightTemperature();

		DayTimeTemperature dayTime = new DayTimeTemperature(morningTemp);
		dayTime.showTemperature("10 Degree Celsius");

		dayTime = new DayTimeTemperature(noonTemp);
		dayTime.showTemperature("15 Degree Celsius");

		dayTime = new DayTimeTemperature(afterNoonTemp);
		dayTime.showTemperature("13 Degree Celsius");

		dayTime = new DayTimeTemperature(eveningTemp);
		dayTime.showTemperature("11 Degree Celsius");

		dayTime = new DayTimeTemperature(nightTemp);
		dayTime.showTemperature("9 Degree Celsius");
	}

}

Run the above test class and see the below output in the console:

Today's temperature at morning : 10 Degree Celsius
Today's temperature at noon : 15 Degree Celsius
Today's temperature at afternoon : 13 Degree Celsius
Today's temperature at evening : 11 Degree Celsius
Today's temperature at night : 9 Degree Celsius

Strategy Design pattern can be applied when you meet the following points:

  • You need to swap algorithm used inside an object at runtime
  • You need to isolate the implementation details of an algorithm from the code that uses it
  • You may want to replace inheritance by composition
  • You may want to follow open/closed principle – you need to introduce new strategy instead of having to change the context

Source Code

Download

Leave a Reply

Your email address will not be published. Required fields are marked *