# Strategy Design Pattern: Clear and Concise with Java Examples

The **Strategy pattern** lets you define a family of algorithms, encapsulate each one, and make them interchangeable. It enables selecting an algorithm at runtime, promoting flexibility and adherence to SOLID principles.

![](https://upload.wikimedia.org/wikipedia/commons/3/39/Strategy_Pattern_in_UML.png align="left")

### Understanding the Class Diagram

* **Context**: Has a `Strategy` object and uses it to delegate the work, without knowing the implementation details.
    
* **Strategy**: An interface defining a method (here called `execute()`), which each concrete strategy implements with its own behavior.
    
* **ConcreteStrategyA / B**: Specific implementations of the strategy, interchangeable at runtime.
    

**How it works**: The `Context` relies on the `Strategy` to perform the task. This allows swapping behaviors easily, promoting flexibility and following the Open/Closed Principle.

### Simple Example

Let’s say we’re implementing a payment system, and we have multiple payment methods:

```java
class PaymentService {
    void pay(String method, int amount) {
        if ("credit".equals(method)) {
            // logic for credit card
        } else if ("paypal".equals(method)) {
            // logic for PayPal
        }
        // more conditions to come...
    }
}
```

Having a long payment method with the needed logic to process multiple payment methods is rigid, grows unwieldy, and violates **Open/Closed Principle** (OCP). Each new method increases **cyclomatic complexity** and requires modifying the existing code.

### Applying the Strategy Pattern

```java
interface PaymentStrategy {
    void pay(int amount);
}

class CreditCardPayment implements PaymentStrategy {
    public void pay(int amount) {
        System.out.println("Paid " + amount + " with credit card");
    }
}

class PayPalPayment implements PaymentStrategy {
    public void pay(int amount) {
        System.out.println("Paid " + amount + " with PayPal");
    }
}

class PaymentService {
    private PaymentStrategy strategy;

    public PaymentService(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

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

    public void process(int amount) {
        strategy.pay(amount);
    }
}
```

✅ This avoids conditionals, respects OCP, and makes each strategy testable and reusable — aligning with **Single Responsibility Principle** (SRP) too.

### Example Usage

```java
PaymentService service = new PaymentService(new CreditCardPayment());
service.processPayment(100);  // Outputs: Paid $100 with Credit Card.

service.setStrategy(new PayPalPayment());
service.processPayment(75);   // Outputs: Paid $75 with PayPal.
```

---

### A Quick Note on Cyclomatic Complexity

**Cyclomatic complexity** increases as your code has more `if-else` branches, making it harder to test, understand, and change safely.

#### ❌ Without Strategy Pattern (Multiple Paths)

```java
javaCopyEditclass PaymentService {
    void pay(String method, int amount) {
        if (method.equals("credit")) {
            System.out.println("Paid with Credit Card");
        } else if (method.equals("paypal")) {
            System.out.println("Paid with PayPal");
        } else if (method.equals("applepay")) {
            System.out.println("Paid with Apple Pay");
        }
    }
}
```

Every new method adds a new branch — more paths, more chances to break something.

#### ✅ With Strategy Pattern (Single Path)

```java
javaCopyEditclass PaymentService {
    private PaymentStrategy strategy;

    public PaymentService(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

    public void process(int amount) {
        strategy.pay(amount); // Always a single, clean path
    }
}
```

No matter how many strategies you add, `process()` always follows one path.  
This makes your code **easier to test, reason about, and extend** — which helps maintain quality as the system grows.

### Functional Programming: A Modern Alternative?

In languages that support **first-class functions**, you can simplify the strategy pattern using lambdas:

```java
Consumer<Integer> creditCard = amount -> System.out.println("Paid " + amount + " with credit card");
Consumer<Integer> paypal = amount -> System.out.println("Paid " + amount + " with PayPal");

void processPayment(Consumer<Integer> strategy, int amount) {
    strategy.accept(amount);
}
```

For short, stateless behaviors, lambdas are concise and flexible. But if the strategy:

* Has internal state
    
* Needs validation logic
    
* Requires encapsulation
    

…then creating a full class (like `CreditCardPayment`) may be more appropriate to uphold **SRP** and **encapsulation**.

---

### When Should You Use the Strategy Pattern?

Look for these **clues**:

#### 1\. **You have multiple** `if-else` or `switch` statements selecting behavior

#### 2\. **You expect the behavior to change at runtime**

Strategy lets you swap logic dynamically — for example, letting a user choose a payment method at runtime.

#### 3\. **You want to follow the Open/Closed Principle**

New behaviors can be added via new strategy classes, without touching existing logic.

#### 4\. **You want to reuse or test behaviors independently**

Each strategy is a standalone unit that’s easier to test and reuse in other parts of the system.

### 💡 Tip: Let the Strategy Pattern Emerge

> Start with the simplest solution. If you notice repeated conditionals or growing complexity, **that’s your cue to refactor** using the Strategy pattern.
> 
> With experience, you’ll start recognizing these patterns earlier and apply them upfront when it makes sense.

### 🧩 Conclusion

The Strategy pattern is one of the simplest and most practical ways to apply the **SOLID principles**. In fact, if you study SOLID first, you’ll see that Strategy is a natural implementation of those ideas in action.  
👉 You can refresh those principles in my article: [SOLID Principles Refresher](https://code-like-a-woman.hashnode.dev/solid-principles-refresher)

By applying this pattern, you get code that is:

* Easier to maintain
    
* Less prone to errors
    
* Simpler to test and extend
    

I think there’s no real downside to using Strategy, as long as you apply it where **flexibility is needed** and don’t over-engineer parts of your code that are meant to stay simple or static.

👉 **Enjoyed this article?**  
Check out the rest of my **Design Patterns** series here:  
🔗 [code-like-a-woman.hashnode.dev/series/design-patterns](https://code-like-a-woman.hashnode.dev/series/design-patterns)
