DEV Community

Naresh Babu
Naresh Babu

Posted on

Strategy Design Pattern

The Strategy Design Pattern is a behavioral design pattern that enables selecting an algorithm's behavior at runtime.

Instead of implementing multiple variations of an algorithm in a single class, it allows you to define a family of algorithms, encapsulate each in its own class, and make them interchangeable.

Components of the Strategy Pattern (UML):

  1. Context Class: Maintains a reference to a Strategy object and interacts with it through a common interface.

    • Example: The User class interacts with different strategies for Quality and AdPolicy.
  2. Strategy Interface: Defines a common interface for all concrete strategies.

    • Example: Quality and ADPolicies are abstract interfaces defining behavior.
  3. Concrete Strategies: Implement the Strategy interface with specific algorithms.

    • Example: FreeUserQuality, PremiumUserQuality, BasicUserQuality, FreeUserAdPolicy, etc.

When to Use the Strategy Pattern

Use the Strategy Pattern when the benefits of flexibility and maintainability outweigh the overhead of managing multiple strategy classes.

  1. Many Algorithms:

    • When you need to define multiple variations of an algorithm or behavior within a single class.
    • Example: Defining video quality for different subscription plans (Free, Basic, Premium).
  2. Runtime Decisions:

    • When the behavior of a class needs to change dynamically based on user input or other runtime conditions.
    • Example: Selecting compression algorithms (ZIP, RAR, 7z) at runtime.
  3. Avoid Excessive Use of if or switch Statements:

    • Replace conditional logic with interchangeable strategy classes.
    • Example: Payment processing (Credit Card, PayPal, UPI) without a massive if-else block.
  4. Encapsulation of Variations:

    • Encapsulate algorithm variations in separate classes to keep the context class clean.
    • Example: Logging strategies (ConsoleLogger, FileLogger, RemoteLogger).
  5. Open/Closed Principle:

    • Ensure the system is open for extension but closed for modification by adding new strategies without altering existing code.
    • Example: Adding a new user type (EnterpriseUserQuality) in the example system.

Example:

from abc import ABC, abstractmethod
from enum import Enum

# Enum for User Types
class UserType(Enum):
    FREE = 0
    BASIC = 1
    PREMIUM = 2

# Strategy Interface for Quality
class Quality(ABC):
    @abstractmethod
    def get_quality(self):
        pass

# Strategy Interface for Ad Policy
class AdPolicy(ABC):
    @abstractmethod
    def has_ads(self):
        pass

# Concrete Strategy for Quality
class FreeUserQuality(Quality):
    def get_quality(self):
        return ['SD']

class BasicUserQuality(Quality):
    def get_quality(self):
        return ['SD', 'HD']

class PremiumUserQuality(Quality):
    def get_quality(self):
        return ['SD', 'HD', 'UHD']

# Concrete Strategy for Ad Policy
class FreeUserAdPolicy(AdPolicy):
    def has_ads(self):
        return True

class BasicUserAdPolicy(AdPolicy):
    def has_ads(self):
        return True

class PremiumUserAdPolicy(AdPolicy):
    def has_ads(self):
        return False

# Context Class
class User:
    def __init__(self, user_type: UserType, quality: Quality, ad_policy: AdPolicy):
        self.user_type = user_type
        self.quality = quality
        self.ad_policy = ad_policy

    def get_quality(self):
        return self.quality.get_quality()

    def has_ads(self):
        return self.ad_policy.has_ads()

# Usage
free_user = User(UserType.FREE, FreeUserQuality(), FreeUserAdPolicy())
basic_user = User(UserType.BASIC, BasicUserQuality(), BasicUserAdPolicy())
premium_user = User(UserType.PREMIUM, PremiumUserQuality(), PremiumUserAdPolicy())

print("Free User Quality:", free_user.get_quality())  # ['SD']
print("Free User Ads:", free_user.has_ads())          # True

print("Premium User Quality:", premium_user.get_quality())  # ['SD', 'HD', 'UHD']
print("Premium User Ads:", premium_user.has_ads())          # False
Enter fullscreen mode Exit fullscreen mode

Advantages of the Strategy Pattern:

  1. Flexibility: Algorithms can be swapped at runtime without altering the context class.
  2. Extensibility: New strategies can be added without modifying existing code.
  3. Readability and Maintenance: Reduces clutter in the main class by delegating logic to specific strategy classes.
  4. Adherence to SOLID Principles: Particularly supports the Open/Closed Principle.

Disadvantages of the Strategy Pattern:

  1. Increased Complexity: Introduces additional classes and objects to manage.
  2. Overhead: If the number of strategies is small or infrequently changed, the pattern might add unnecessary complexity.

Additional Examples

  1. Sorting Algorithms: Using different sorting strategies (e.g., QuickSort, MergeSort, BubbleSort) dynamically.
  2. Discount Calculation: Applying different discount strategies (FlatDiscount, PercentageDiscount) based on user type.
  3. Authentication Mechanisms: Switching between different authentication methods (OAuth, JWT, BasicAuth).

Top comments (0)