Python Strategy Design Pattern

1. Definition

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

2. Problem Statement

Consider a situation where you have a class with a method that performs a specific action. Over time, you realize that the method's behavior needs to vary. Implementing every variation within the class can lead to bulky code and numerous condition checks.

3. Solution

Separate the variable behavior (algorithm) into its own classes. Define these behaviors as strategies. The main class, often referred to as the context, will have a reference to a strategy object and will delegate the task to it.

4. Real-World Use Cases

1. Different compression algorithms (ZIP, RAR, TAR) for file compressors.

2. Various payment methods (Credit Card, PayPal, Stripe) in e-commerce applications.

3. Different behaviors for sorting collections.

5. Implementation Steps

1. Define a strategy interface that describes how strategies will be used.

2. Implement concrete strategies that adhere to the strategy interface.

3. Create a context class that contains a reference to a strategy and delegates the work to it.

6. Implementation in Python

# Strategy Interface
class CompressionStrategy:
    def compress(self, data):
        pass
# Concrete Strategies
class ZipCompression(CompressionStrategy):
    def compress(self, data):
        return f"Compressed using ZIP: {data}"
class RarCompression(CompressionStrategy):
    def compress(self, data):
        return f"Compressed using RAR: {data}"
# Context
class Compressor:
    def __init__(self, strategy: CompressionStrategy):
        self.strategy = strategy
    def set_strategy(self, strategy: CompressionStrategy):
        self.strategy = strategy
    def execute_compression(self, data):
        return self.strategy.compress(data)
# Client code
data = "sample_data"
compressor = Compressor(ZipCompression())
print(compressor.execute_compression(data))
compressor.set_strategy(RarCompression())
print(compressor.execute_compression(data))

Output:

Compressed using ZIP: sample_data
Compressed using RAR: sample_data

Explanation:

1. We define a CompressionStrategy interface that specifies a compress method.

2. Concrete strategies ZipCompression and RarCompression implement the compress method with their specific algorithms.

3. The Compressor class (context) contains a reference to a strategy object. It delegates the compression task to whichever strategy has been set.

4. The client can easily switch between strategies by calling set_strategy.

7. When to use?

Use the Strategy Pattern when:

1. Many related classes differ only in their behavior. Strategies provide a way to configure a class with one of many behaviors.

2. You need different variants of an algorithm. For instance, you might define algorithms reflecting different space/time trade-offs.

3. An algorithm uses data that clients shouldn't know about. Use the Strategy pattern to avoid exposing complex, algorithm-specific data structures.

4. A class defines many behaviors, and these appear as multiple conditional statements in its operations. Instead of many conditionals, move related conditional branches into their own strategy class.


Comments