Other Tutorials

Strategy Design Pattern In Java

Introduction:

The strategy design pattern is a behavioral pattern in which we have multiple algorithms/strategies for achieving a task and which algorithm/strategy to use is left for the client to choose. The various algorithm options are encapsulated in individual classes.

In this tutorial, we’ll learn to implement the strategy design pattern in Java.

UML Representation:

Let’s first start by looking at the UML representation of the strategy design pattern:

Strategy Design Pattern

Here, we have:

  • Strategy: an interface defining the common operation we intend to perform
  • ConcreteStrategy: these are the implementation classes that use different algorithms to carry out the operation defined in the Strategy interface
  • Context: anything that requires changing behaviors and holds a reference to a Strategy

One popular example of the Strategy pattern in JDK is the usage of java.util.Comparator in the Collections.sort() method. We can think of Collections.sort() method to be the context and the java.util.Comparator instance that we pass-in as the strategy for sorting objects.

Implementing the Strategy Pattern:

As we know, any shopping website offers multiple payment options. So, let’s use this example to implement the strategy pattern.

We’ll first define our PaymentStrategy interface:

public interface PaymentStrategy {
    void pay(Shopper shopper);
}

Now, let’s define the two most common modes of payments, Cash on Delivery and Card payment, as the two concrete strategy classes:

public class CashOnDeliveryStrategy implements PaymentStrategy {
    @Override
    public void pay(Shopper shopper) {
        double amount = shopper.getShoppingCart().getTotal();
        System.out.println(shopper.getName() + " selected Cash On Delivery for Rs." + amount );
    }
}

public class CardPaymentStrategy implements PaymentStrategy {
    @Override
    public void pay(Shopper shopper) {
        CardDetails cardDetails = shopper.getCardDetails();
        double amount = shopper.getShoppingCart().getTotal();
        completePayment(cardDetails, amount);
        System.out.println("Credit/Debit card Payment of Rs. " + amount + " made by " + shopper.getName());
    }

    private void completePayment(CardDetails cardDetails, double amount) { ... }
}

Implementing Context:

Having defined our strategy classes, let’s now define a PaymentContext class:

public class PaymentContext {

    private PaymentStrategy strategy;

    public PaymentContext(PaymentStratgey strategy) {
        this.strategy = strategy;
    }

    public void makePayment(Shopper shopper) {
        this.strategy.pay(shopper);
    }
}

Also, our Shopper class would look similar to:

public class Shopper {

    private String name;
    private CardDetails cardDetails;
    private ShoppingCart shoppingCart;

    //suitable constructor , getters and setters
    
    public void addItemToCart(Item item) {
        this.shoppingCart.add(item);
    }

    public void payUsingCOD() {
        PaymentContext pymtContext = new PaymentContext(new CashOnDeliveryStrategy());
        pymtContext.makePayment(this);
    }

    public void payUsingCard() {
        PaymentContext pymtContext = new PaymentContext(new CardPaymentStrategy());
        pymtContext.makePayment(this); 
    }
}

A Shopper in our system can pay using one of the available strategies for his/her purchases. For our example, our PaymentContext class accepts the selected payment strategy and then invokes the pay() method for that strategy.

Strategy vs State Design Pattern:

Both strategy and state design patterns are interface based patterns and might look similar but have some important differences:

  • State design pattern defines various states where the strategy pattern talks more about different algorithms
  • In a state pattern, there’s a transition from one state to another. On the other hand, all the strategy classes in a strategy pattern are independent of each other

Please feel free to further explore the State Design Pattern.

Conclusion:

With this quick tutorial, we now know how to implement a Strategy design pattern.

It’s one of the most commonly used design patterns and obeys the Open/Closed principle. So, to add a new strategy, we can simply create an additional strategy class. However, please note that we’ll have to update the client code as well here as the client chooses the strategy to be invoked.

Be the First to comment.

Leave a Comment

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