Python中的策略设计模式
#python #codequality #designpatterns

在开发软件应用程序(根据应用程序类型的不同)时,在编写实际代码之前,在开发的设计阶段需要回答问题。这些问题之一是,如何构建我的应用程序?软件设计模式可以帮助回答这个结构问题。设计模式有助于我们以使其可靠,可维护和易于理解的方式构建应用程序。

设计模式是用于修复代码库中与结构有关的问题的高级概念。它们不是特定于语言的,因此您可以使用任何支持对象的编程的语言使用它们。在本文中,我们将了解一种流行的设计模式,称为策略模式。

先决条件

在进行战略模式之前,您需要对面向对象的编程有基本的了解。类和对象是设计模式概念的核心部分。

什么是策略模式?

策略模式是定义算法集合的设计模式,并允许这些算法在运行时可以互换。根据有关设计模式的书,Eric Freeman&Elisabeth Robson的“Head First: Design Patterns”

策略模式定义了一个算法家族,封装了每种算法,并使其可互换。策略使该算法与使用它的客户的独立性不同。

在某些情况下,您可以拥有多种方法来完成特定任务。这些不同的方式是算法。传统上,您倾向于将有条件的陈述(IF-ELSE)视为确定要使用哪种算法的一种方式。此方法不是编写良好和干净的代码的更好方法。同样,随着算法数量的增加,代码变得更长,更难维护。

在这种情况下,策略模式是一个很好的解决方案。策略模式使您可以定义包含各种算法的实现的称为策略的类。主类有对策略的引用,然后您可以将您的首选策略传递给上下文。让我们看一下策略模式的示例实现。

执行

让我们说我们有一个电子商务应用程序,可以在其中注册产品。在注册这些产品时,我们希望为每个产品生成独特的ID。我们希望能够使用不同的标准和参数生成ID。我们将使用策略设计模式来制定两个可切换策略来生成产品ID。首先,我们有一个RandomStrategy,该RandomStrategy将产品ID作为随机字符串生成。相比之下,另一个DerivedStrategy使用产品的详细信息(例如日期时间,类别和sku。

)生成产品ID。

我们有我们的strategy.py文件。该文件包含用于生成产品ID及其不同实现的算法家族(在我们的情况下,strategies)。

from abc import ABC, abstractmethod
from datetime import datetime
import string
import secrets


class ProductIdStrategy(ABC):
    """An interface for strategy type"""

    @abstractmethod
    def generate_product_id() -> None:
        """Each class will have its own implementation of this function"""
        pass


class RandomStrategy(ProductIdStrategy):

    def generate_product_id(self) -> str:
        limit = 12
        product_id = "".join(secrets.choice(
            string.ascii_uppercase+string.digits) for i in range(limit))
        return product_id


class DerivedStrategy(ProductIdStrategy):
    ''' The Derived Strategy will derive the product id from the id, category and SKU of the product'''

    def __init__(self, product) -> None:
        super().__init__()
        self.product = product

    def generate_product_id(self) -> str:
        id = self.product["id"]
        # Get the first 3 characters of the category
        category = self.product["category"][:3].upper()
        sku = self.product["sku"]
        # Get the date string and replace remove the hyphens
        date = datetime.strptime(self.product["date_added"], "%Y-%m-%d").date().__str__().replace("-", "")
        product_id = "".join([category, "-", date, "-", sku, id,])
        return product_id

然后我们有一个product.py文件。在此文件中,我们可以互换实施不同的策略。

from strategy import *

class Product:
    _strategy: ProductIdStrategy

    def __init__(self, strategy: ProductIdStrategy) -> None:
        self._strategy = strategy

    def get_product_id(self) -> str:
        return self._strategy.generate_product_id()

if __name__ == "__main__":
    stock = {
        "id": "1",
        "name": "Maxi Lotion",
        "category": "Skin Care",
        "sku": "6134752",
        "date_added": "2022-12-28",
    }

    ''' Generating the product id using the random strategy '''
    strategy = RandomStrategy()
    product = Product(strategy)
    print("The product id using the Random Strategy is : " + product.get_product_id())

    '''
        Generating the product id using the derived strategy
        The product is passed into to the strategy so as to extract information from it
    '''
    strategy = DerivedStrategy(stock)
    product = Product(strategy)
    print("The product id using the Derived Strategy is : " + product.get_product_id())

结果显示了两个产品ID。一个是使用Random Strategy生成的,另一个是用Derived Strategy生成的。
Image description

结论

在本文中,我们了解了策略模式是什么以及如何实施它。借助策略设计模式,我们可以在运行时在算法之间切换,而无需更改代码。策略模式可用于选择应用程序的行为,而不是使用条件表达式。

我希望本文向您展示如何实施策略设计模式。您可以在此GitHub存储库中获取示例代码。