Design Pattern – Strategy

Md Sajjad Hosen Noyon

9 May, 2025

The Strategy Design Pattern is a powerful pattern in the world of object-oriented programming. It provides a flexible way to encapsulate, choose from multiple algorithms, and swap the behavior of an object at runtime, enabling code to be more adaptable and easier to maintain. The core idea behind this behavioral pattern is to separate the algorithms from the main object. This allows the object to delegate the algorithm’s behavior to one of its contained strategies.

Characteristics of the Strategy Design Pattern?

The Strategy Design Pattern exhibits several key characteristics that make it distinctive and effective for managing algorithm variations in software systems:

  • It defines a family of algorithms: The pattern allows you to encapsulate multiple algorithms or behaviors into separate classes, known as strategies.
  • It encapsulates behaviors: Each strategy encapsulates a specific behavior or algorithm, providing a clean and modular way to manage different variations or implementations.
  • It enables dynamic behavior switching: The pattern enables a client to switch between different strategies at runtime, allowing for flexible and dynamic behavior changes.
  • It promotes object collaboration: The pattern encourages collaboration between a context object and strategy objects, where the context delegates the execution of a behavior to a strategy object.

Overall, the Strategy pattern is a useful design pattern that allows the behavior of an object to be selected dynamically at runtime, providing flexibility, modularity, and testability.

Components of the Strategy Design Pattern

The Strategy Design Pattern consists of four primary components:

Context: The object that will delegate its behavior. The context maintains a reference to a strategy object and interacts with it through an interface.

Strategy Interface: The interface that defines the behavior for all strategies. The strategies implement this interface to provide their unique implementation.

Strategies: The classes that implement the Strategy interface. Each strategy encapsulates a specific behavior that the context can switch at runtime.

Client: The Client is responsible for creating, selecting, and configuring the appropriate strategy and providing it to the Context.

Code Example

Let’s consider the following code example:

				
					public class PaymentProcessor {
    private PaymentType paymentType;

    public void processPayment(double amount) {
        if (paymentType == PaymentType.CREDIT_CARD) {
            System.out.println("Processing credit card payment of amount " + amount);
        } else if (paymentType == PaymentType.DEBIT_CARD) {
            System.out.println("Processing debit card payment of amount " + amount);
        } else if (paymentType == PaymentType.PAYPAL) {
            System.out.println("Processing PayPal payment of amount " + amount);
        } else {
            throw new IllegalArgumentException("Invalid payment type");
        }
    }

    public void setPaymentType(PaymentType paymentType) {
        this.paymentType = paymentType;
    }
}

enum PaymentType {
    CREDIT_CARD,
    DEBIT_CARD,
    PAYPAL
}
				
			

In this code, the PaymentProcessor class has a processPayment method that takes a parameter payment amount and processes the payment. The setPaymentType method sets the payment type. The processPayment method then checks the process type and processes the payment accordingly.

The problem with this approach is that it violates the Open-Closed principle. In this code, if you want to add a new payment method, you have to modify the processPayment method, and it also determines the process payment type through conditional statements, which violates the Open-Closed principle.

To fix this problem, we can use the Strategy Design Pattern. First, define a common interface for all payment strategies, which in this case is the PaymentStrategy interface:

				
					public interface PaymentStrategy {
    void processPayment(double amount);
}
				
			

Then define the implementation of the PaymentStrategy interface for each payment strategy.

				
					public class CreditCardPaymentStrategy implements PaymentStrategy {
    public void processPayment(double amount) {
        System.out.println("Processing credit card payment of amount " + amount);
    }
}

public class DebitCardPaymentStrategy implements PaymentStrategy {
    public void processPayment(double amount) {
        System.out.println("Processing debit card payment of amount " + amount);
    }
}

public class PaypalPaymentStrategy implements PaymentStrategy {
    public void processPayment(double amount) {
        System.out.println("Processing PayPal payment of amount " + amount);
    }
}
				
			

Finally, update the PaymentProcessor class (Context) to take a PaymentStrategy object in its constructor, which is used to process the payment:

				
					public class PaymentProcessor {
    private PaymentStrategy paymentStrategy;

    public PaymentProcessor(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }

    public void processPayment(double amount) {
        paymentStrategy.processPayment(amount);
    }
}
				
			

This implementation follows the Open-Closed Principle as well as the Strategy Pattern because you can add new payment types by creating new implementations of the PaymentStrategy interface without modifying the existing code.

References
Conclusion

This blog has covered characteristics, components, and implementation of Strategy Design Patterns. If you want to learn more, have a look at the reference section.

Thanks for reading.

See you! 👋

Md Sajjad Hosen Noyon

9 May, 2025