Home >Backend Development >Python Tutorial >Strategy Design Pattern

Strategy Design Pattern

Barbara Streisand
Barbara StreisandOriginal
2024-11-27 15:05:12692browse

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

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).

The above is the detailed content of Strategy Design Pattern. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn