# Strategy Pattern: Swap Algorithms Runtime

# Strategy Pattern: Swap Algorithms at Runtime

## Problem

Applications often need to perform operations using different algorithms that can vary based on runtime conditions. Without proper design, this leads to:

- **Massive conditional statements** scattered throughout code
- **Tight coupling** between client code and algorithm implementations
- **Difficult maintenance** when adding new algorithms
- **Violation of Open/Closed Principle** - code must be modified for each new algorithm
- **Code duplication** across similar algorithm implementations

**Example**: A payment processing system needs to support multiple payment methods (credit card, PayPal, cryptocurrency). Without proper abstraction, you'd have nested if-else statements checking payment type everywhere.

```java
// ❌ Without Strategy Pattern
if (paymentType.equals("CREDIT_CARD")) {
    // credit card logic
} else if (paymentType.equals("PAYPAL")) {
    // PayPal logic
} else if (paymentType.equals("CRYPTO")) {
    // crypto logic
}
```

## Solution

The **Strategy Pattern** defines a family of algorithms, encapsulates each one, and makes them interchangeable. It lets the algorithm vary independently from clients that use it.

**Key Components**:

1. **Strategy Interface**: Defines common algorithm interface
2. **Concrete Strategies**: Implement specific algorithms
3. **Context**: Uses a strategy to execute algorithms
4. **Client**: Selects and configures appropriate strategy

**Benefits**:
- ✅ Eliminates conditional logic
- ✅ Easy to add new algorithms without modifying existing code
- ✅ Algorithms can be swapped at runtime
- ✅ Follows Open/Closed and Single Responsibility principles
- ✅ Improves testability

## Code Implementation

### 1. Strategy Interface

```java
/**
 * Strategy interface defining the contract for all payment strategies
 */
public interface PaymentStrategy {
    boolean pay(double amount);
    String getPaymentMethod();
}
```

### 2. Concrete Strategies

```java
/**
 * Credit Card payment strategy
 */
public class CreditCardStrategy implements PaymentStrategy {
    private String cardNumber;
    private String cvv;
    private String expiryDate;

    public CreditCardStrategy(String cardNumber, String cvv, String expiryDate) {
        this.cardNumber = cardNumber;
        this.cvv = cvv;
        this.expiryDate = expiryDate;
    }

    @Override
    public boolean pay(double amount) {
        System.out.println("Processing credit card payment of $" + amount);
        System.out.println("Card: " + maskCardNumber(cardNumber));
        
        // Validate card details
        if (!isValidCard()) {
            System.out.println("❌ Invalid card details");
            return false;
        }
        
        System.out.println("✅ Payment successful via Credit Card");
        return true;
    }

    @Override
    public String getPaymentMethod() {
        return "Credit Card";
    }

    private boolean isValidCard() {
        return cardNumber.length() == 16 && cvv.length() == 3;
    }

    private String maskCardNumber(String card) {
        return card.substring(0, 4) + "****" + card.substring(12);
    }
}

/**
 * PayPal payment strategy
 */
public class PayPalStrategy implements PaymentStrategy {
    private String email;
    private String password;

    public PayPalStrategy(String email, String password) {
        this.email = email;
        this.password = password;
    }

    @Override
    public boolean pay(double amount) {
        System.out.println("Processing PayPal payment of $" + amount);
        System.out.println("Account: " + email);
        
        if (!authenticate()) {
            System.out.println("❌ PayPal authentication failed");
            return false;
        }
        
        System.out.println("✅ Payment successful via PayPal");
        return true;
    }

    @Override
    public String getPaymentMethod() {
        return "PayPal";
    }

    private boolean authenticate() {
        // Simulate authentication
        return email.contains("@") && password.length() >= 6;
    }
}

/**
 * Cryptocurrency payment strategy
 */
public class CryptoStrategy implements PaymentStrategy {
    private String walletAddress;
    private String privateKey;

    public CryptoStrategy(String walletAddress, String privateKey) {
        this.walletAddress = walletAddress;
        this.privateKey = privateKey;
    }

    @Override
    public boolean pay(double amount) {
        System.out.println("Processing cryptocurrency payment of $" + amount);
        System.out.println("Wallet: " + maskWallet(walletAddress));
        
        if (!validateWallet()) {
            System.out.println("❌ Invalid wallet");
            return false;
        }
        
        System.out.println("✅ Payment successful via Cryptocurrency");
        return true;
    }

    @Override
    public String getPaymentMethod() {
        return "Cryptocurrency";
    }

    private boolean validateWallet() {
        return walletAddress.length() >= 26 && privateKey.length() >= 64;
    }

    private String maskWallet(String wallet) {
        return wallet.substring(0, 6) + "..." + wallet.substring(wallet.length() - 6);
    }
}
```

### 3. Context Class

```java
/**
 * Context class that uses a payment strategy
 */
public class PaymentProcessor {
    private PaymentStrategy strategy;
    private double amount;

    public PaymentProcessor(double amount) {
        this.amount = amount;
    }

    /**
     * Set the payment strategy at runtime
     */
    public void setPaymentStrategy(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

    /**
     * Execute payment using the current strategy
     */
    public boolean processPayment() {
        if (strategy == null) {
            System.out.println("❌ No payment strategy selected");
            return false;
        }
        
        System.out.println("\n--- Processing Payment ---");
        System.out.println("Amount: $" + amount);
        System.out.println("Method: " + strategy.getPaymentMethod());
        
        return strategy.pay(amount);
    }

    public double getAmount() {
        return amount;
    }
}
```

### 4. Client Usage

```java
/**
 * Demonstration of Strategy Pattern
 */
public class StrategyPatternDemo {
    public static void main(String[] args) {
        double orderAmount = 99.99;
        PaymentProcessor processor = new PaymentProcessor(orderAmount);

        // Strategy 1: Credit Card
        System.out.println("=== SCENARIO 1: Credit Card Payment ===");
        PaymentStrategy creditCard = new CreditCardStrategy(
            "1234567890123456", 
            "123", 
            "12/25"
        );
        processor.setPaymentStrategy(creditCard);
        processor.processPayment();

        // Strategy 2: PayPal
        System.out.println("\n=== SCENARIO 2: PayPal Payment ===");
        PaymentStrategy paypal = new PayPalStrategy(
            "user@example.com", 
            "securePassword123"
        );
        processor.setPaymentStrategy(paypal);
        processor.processPayment();

        // Strategy 3: Cryptocurrency
        System.out.println("\n=== SCENARIO 3: Cryptocurrency Payment ===");
        PaymentStrategy crypto = new CryptoStrategy(
            "1A1z7agoat2Bt89ZqNQrW5QJ89r3xqBc7L",
            "5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf"
        );
        processor.setPaymentStrategy(crypto);
        processor.processPayment();

        // Strategy 4: Invalid Credit Card
        System.out.println("\n=== SCENARIO 4: Invalid Credit Card ===");
        PaymentStrategy invalidCard = new CreditCardStrategy(
            "1234", 
            "12", 
            "12/25"
        );
        processor.setPaymentStrategy(invalidCard);
        processor.processPayment();
    }
}
```

### Output

```
=== SCENARIO 1: Credit Card Payment ===

--- Processing Payment ---
Amount: $99.99
Method: Credit Card
Processing credit card payment of $99.99
Card: 1234****3456
✅ Payment successful via Credit Card

=== SCENARIO 2: PayPal Payment ===

--- Processing Payment ---
Amount: $99.99
Method: PayPal
Processing PayPal payment of $99.99
Account: user@example.com
✅ Payment successful via PayPal

=== SCENARIO 3: Cryptocurrency Payment ===

--- Processing Payment ---
Amount: $99.99
Method: Cryptocurrency
Processing cryptocurrency payment of $99.99
Wallet: 1A1z7a...qBc7L
✅ Payment successful via Cryptocurrency

=== SCENARIO 4: Invalid Credit Card ===

--- Processing Payment ---
Amount: $99.99
Method: Credit Card
Processing credit card payment of $99.99
Card: 1234****1234
❌ Invalid card details
```

## Real-World Applications

| Domain | Example |
|--------|---------|
| **Sorting** | Different sorting algorithms (QuickSort, MergeSort, BubbleSort) |
| **Compression** | ZIP, RAR, 7Z compression strategies |
| **Routing** | GPS navigation algorithms (fastest, shortest, scenic) |
| **Authentication** | OAuth, JWT, Basic Auth strategies |
| **Caching** | LRU, LFU, FIFO cache eviction strategies |
| **Reporting** | PDF, Excel, JSON export formats |

## Key Takeaways

✅ **Encapsulation**: Each algorithm is encapsulated in its own class  
✅ **Runtime Flexibility**: Switch algorithms without recompiling  
✅ **Maintainability**: Adding new strategies doesn't affect existing code  
✅ **Testability**: Each strategy can be tested independently  
✅ **SOLID Principles**: Adheres to Open/Closed and Dependency Inversion principles
