Exploring the Strategy Design Pattern

Salitha Ekanayaka
5 min readJun 13, 2024

--

A strategy pattern is a behavioral design pattern that allows user to define and encapsulates a family of algorithms, making them interchangeable.

This pattern allows the algorithm to alter independently of the users that use it.

Overall, the Strategy pattern is a useful for enabling the dynamic behavior of an object at a selected runtime, providing flexibility, modularity, and testability.

Characteristics of the Strategy Design Pattern

The Strategy Design Pattern has unique characteristics that make it efficient for handling algorithm changes in software systems.

  1. Encapsulation of algorithms : Allows the user to encapsulate several algorithms into independent classes. Those classes are referred to as strategies.
  2. Encapsulates behaviors of algorithms: Encapsulating algorithms allows for a clean and versatile approach to code implementations, with each strategy having its own unique behavior.
  3. Interchangeability: Strategies of patterns can be switched at the runtime without altering the client which enables flexible and dynamic changes
  4. Promotes object collaboration: There can be collaboration between a context object and strategy objects in which the context transferred the execution of a behavior to the strategy object

Components of the Strategy Design Pattern

Context

Maintains a reference to a Strategy object and is configured with a ConcreteStrategy object. It can use this reference to call the algorithm defined by the strategy.

Strategy Interface

The Strategy Interface is an interface or abstract class that defines a set of methods that all concrete strategies must implement, allowing the Context to use this interface to call the algorithm defined by a concrete strategy.

By defining a common interface, the Strategy Interface decouples the Context from the concrete strategies, promoting flexibility and modularity in the design.

Concrete Strategies

Classes that implement the Strategy interface. Each concrete strategy implements an algorithm. Each concrete strategy follows a specific algorithm or behavior to complete the task defined by the Strategy Interface.

Concrete strategies encapsulate the details of their respective algorithms and provide a method for executing the task.

Client

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

Communication in the Strategy Design Pattern

Client to Context

  • Through interaction with the Context, the Client commences the task execution process.
  • It selects and delivers the suitable approach for the given context.
  • Before delivering the strategy, the client may adjust it.

Context to Strategy

  • The Context assigns the job to the chosen strategy and maintains a reference to it.
  • It invokes a method on the strategy, triggering the particular algorithm to execute itself.

Strategy to Context

The strategy completes its execution and may return a result or perform actions.

It communicates the result or relevant information back to the Context for further processing.

Strategy Interface as Contract

  • The Strategy Interface provides the procedures that any concrete strategy needs to follow.
  • The Context uses this interface, ensuring interchangeability and decoupling.

Decoupled Communication

  • The Context doesn’t need to know the details of each strategy’s implementation.
  • Strategies can be swapped or replaced without affecting the Client or other strategies, as long as they adhere to the interface.

Example

Let’s say there’s a task management system for an IT company where different roles (Developers, QE Engineers, and Business Analysts) can complete different tasks using different strategies. The Strategy Design Pattern will allow the system to switch between different task completion strategies dynamically.

Code Implementation

// Strategy Interface
public interface TaskCompletionStrategy {
void completeTask(String task);
}
// Concrete Strategy A: Developer Task Completion
public class DeveloperTaskCompletionStrategy implements TaskCompletionStrategy {
@Override
public void completeTask(String task) {
System.out.println("Developer is completing the task: " + task);
}
}

// Concrete Strategy B: QE Engineer Task Completion
public class QETaskCompletionStrategy implements TaskCompletionStrategy {
@Override
public void completeTask(String task) {
System.out.println("QE Engineer is testing the task: " + task);
}
}

// Concrete Strategy C: Business Analyst Task Completion
public class BATaskCompletionStrategy implements TaskCompletionStrategy {
@Override
public void completeTask(String task) {
System.out.println("Business Analyst is analyzing the task: " + task);
}
}
// Context
public class TaskManager {
private TaskCompletionStrategy taskCompletionStrategy;

public TaskManager(TaskCompletionStrategy taskCompletionStrategy) {
this.taskCompletionStrategy = taskCompletionStrategy;
}

public void setTaskCompletionStrategy(TaskCompletionStrategy taskCompletionStrategy) {
this.taskCompletionStrategy = taskCompletionStrategy;
}

public void completeTask(String task) {
taskCompletionStrategy.completeTask(task);
}
}
public class StrategyPatternExample {
public static void main(String[] args) {
TaskManager taskManager;

// Task to be completed
String task = "Implement login feature";

// Using Developer Task Completion Strategy
taskManager = new TaskManager(new DeveloperTaskCompletionStrategy());
taskManager.completeTask(task); // Output: Developer is completing the task: Implement login feature

// Using QE Engineer Task Completion Strategy
taskManager.setTaskCompletionStrategy(new QETaskCompletionStrategy());
taskManager.completeTask(task); // Output: QE Engineer is testing the task: Implement login feature

// Using Business Analyst Task Completion Strategy
taskManager.setTaskCompletionStrategy(new BATaskCompletionStrategy());
taskManager.completeTask(task); // Output: Business Analyst is analyzing the task: Implement login feature
}
}

Other examples for Strategy Design Pattern

Payment processing System

  1. Client: User
  2. Context: Make a Payment
  3. Strategy interface: Interface that define the payment function with amount
  4. Strategies: Credit card, Debit Card, Pay on delivery

Data Compression

  1. Client: Data that needed to compress
  2. Context: Use compression strategy to compress data
  3. Strategy interface: Interface that define the compress function
  4. Strategies: Zip compress, Rar compress, Gzip compress

When to use this Pattern

  • When a user has multiple algorithms for a specific task and wants to switch between them.
  • When the user needs to isolate the implementation details of a specific algorithm from the source.
  • When a class has multiple actions and conditional statements within its operations.

Conclusion

The Strategy Design Pattern offers a solid framework for improving adaptability and flexibility in software design. Encapsulating algorithms in interchangeable strategy classes encourages manageable and extensible code. This pattern is especially effective for many tasks such as sorting, payment processing, and data compression. Proper implementation can greatly improve your codebase’s capacity to adapt to new requirements. However, you must first determine whether it is appropriate for your project. When used properly, it produces cleaner, more efficient software. Use the Strategy Design Pattern in your projects to get its benefits directly.

Reference

Thank you!

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

No responses yet

Write a response