别院牧志知识库 别院牧志知识库
首页
  • 基础

    • 全栈之路
    • 😎Awesome资源
  • 进阶

    • Python 工匠系列
    • 高阶知识点
  • 指南教程

    • Socket 编程
    • 异步编程
    • PEP 系列
  • Python 面试题
  • 2025 面试记录
  • 2022 面试记录
  • 2021 面试记录
  • 2020 面试记录
  • 2019 面试记录
  • 数据库索引原理
  • 基金

    • 基金知识
    • 基金经理
  • 细读经典

    • 德隆-三个知道
    • 孔曼子-摊大饼理论
    • 配置者说-躺赢之路
    • 资水-建立自己的投资体系
    • 反脆弱
  • Git 参考手册
  • 提问的智慧
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
首页
  • 基础

    • 全栈之路
    • 😎Awesome资源
  • 进阶

    • Python 工匠系列
    • 高阶知识点
  • 指南教程

    • Socket 编程
    • 异步编程
    • PEP 系列
  • Python 面试题
  • 2025 面试记录
  • 2022 面试记录
  • 2021 面试记录
  • 2020 面试记录
  • 2019 面试记录
  • 数据库索引原理
  • 基金

    • 基金知识
    • 基金经理
  • 细读经典

    • 德隆-三个知道
    • 孔曼子-摊大饼理论
    • 配置者说-躺赢之路
    • 资水-建立自己的投资体系
    • 反脆弱
  • Git 参考手册
  • 提问的智慧
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 辨析

  • Sockets编程

  • Django

  • stackoverflow

  • Flask

  • 全栈之路

  • 面试

  • 代码片段

  • 异步编程

  • 😎Awesome资源

  • PEP

  • Python工匠系列

  • 高阶知识点

  • Python 学习资源待整理
  • 设计模式

    • Python 设计模式
    • 装饰器模式
    • 抽象工厂模式
    • 建造者模式/生成器模式
    • 原型模式
    • 单例模式
    • 设计模式(2)——工厂方法模式
    • 设计模式(3)——抽象工厂模式
    • 设计模式(4)——模板方法模式
    • 设计模式(5)——代理模式
    • 设计模式(6)——建造者模式
    • 设计模式(7)——策略模式
      • 基本思想和原则
      • 动机
      • 实现
      • 上下文类的作用
        • 1. 封装算法选择逻辑
        • 2. 运行时策略切换
        • 3. 解耦客户端与策略实现
        • 4. 统一接口调用
        • 简单示例
        • 总结
      • 优点
      • 缺点
      • 实践
      • 参考来源
    • 设计模式(8)——命令模式
    • 设计模式(9)——原型模式
    • 设计模式(10)——中介者模式
    • 设计模式(11)——责任链模式
    • 设计模式(12)——装饰器模式
    • 设计模式(13)——适配器模式
    • 设计模式(14)——迭代器模式
    • 设计模式(15)——观察者模式
    • 设计模式(16)——外观模式
    • 设计模式(17)——状态模式
    • 设计模式(18)——桥接模式
    • 设计模式(19)——享元模式
    • 设计模式(20)——解释器模式
    • 设计模式(21)——组合模式
    • 设计模式(23)——备忘录模式
    • Python 全栈之路系列之单例设计模式
    • 设计模式(22)——访问者模式
    • 工厂方法模式
    • Python 设计模式资源收集
  • 好“艹蛋”的 Python 呀!
  • FIFO | 待学清单📝
  • pip 安装及使用
  • 数据分析

  • 源码阅读计划

  • OOP

  • 关于 python 中的 setup.py
  • 并行分布式框架 Celery
  • 七种武器,让你的代码提高可维护性
  • 使用 pdb 调试 Python 代码
  • 每周一个 Python 标准库
  • 🐍Python
  • 设计模式
佚名
2017-12-08
目录

设计模式(7)——策略模式

本文介绍策略模式的概念和应用。

# 基本思想和原则

定义一组算法,将每个算法都封装起来,使它们之间可以互换。

策略模式(Strategy pattern)鼓励使用多种算法来解决一个问题,其杀手级特性是能够在运行时透明地切换算法(客户端代码对变化无感知)。因此,如果你有两种算法,并且知道其中一种对少量输入效果更好,另一种对大量输入效果更好,则可以使用策略模式在运行时基于输入数据决定使用哪种算法

# 动机

当一个操作中可以使用多种算法相互替换时,可以挨个实现各个算法,然后用一个上下文封装起来,当需要执行操作时,选择一个策略传入上下文即可。

# 实现

from __future__ import annotations

from typing import Callable


class DiscountStrategyValidator:  # Descriptor class for check perform
    @staticmethod
    def validate(obj: Order, value: Callable) -> bool:
        try:
            if obj.price - value(obj) < 0:
                raise ValueError(
                    f"Discount cannot be applied due to negative price resulting. {value.__name__}"
                )
        except ValueError as ex:
            print(str(ex))
            return False
        else:
            return True

    def __set_name__(self, owner, name: str) -> None:
        self.private_name = f"_{name}"

    def __set__(self, obj: Order, value: Callable = None) -> None:
        if value and self.validate(obj, value):
            setattr(obj, self.private_name, value)
        else:
            setattr(obj, self.private_name, None)

    def __get__(self, obj: object, objtype: type = None):
        return getattr(obj, self.private_name)


class Order:
    discount_strategy = DiscountStrategyValidator()

    def __init__(self, price: float, discount_strategy: Callable = None) -> None:
        self.price: float = price
        self.discount_strategy = discount_strategy

    def apply_discount(self) -> float:
        if self.discount_strategy:
            discount = self.discount_strategy(self)
        else:
            discount = 0

        return self.price - discount

    def __repr__(self) -> str:
        return f"<Order price: {self.price} with discount strategy: 
        {getattr(self.discount_strategy,'__name__',None)}>"


def ten_percent_discount(order: Order) -> float:
    return order.price * 0.10


def on_sale_discount(order: Order) -> float:
    return order.price * 0.25 + 20


def main():
    """
    >>> order = Order(100, discount_strategy=ten_percent_discount)
    >>> print(order)
    <Order price: 100 with discount strategy: ten_percent_discount>
    >>> print(order.apply_discount())
    90.0
    >>> order = Order(100, discount_strategy=on_sale_discount)
    >>> print(order)
    <Order price: 100 with discount strategy: on_sale_discount>
    >>> print(order.apply_discount())
    55.0
    >>> order = Order(10, discount_strategy=on_sale_discount)
    Discount cannot be applied due to negative price resulting. on_sale_discount
    >>> print(order)
    <Order price: 10 with discount strategy: None>
    """


if __name__ == "__main__":
    import doctest

    doctest.testmod()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

可以看到策略模式和工厂模式很像。但其实两个的差别很微妙,工厂模式是直接创建具体的对象并用该对象去执行相应的动作。简单工厂模式侧重于生成对象。

而策略模式将这个操作给了 Context 类,没有创建具体的对象,实现的代码的进一步封装,客户端代码并不需要知道具体的实现过程。 策略模式中注重具体算法的实现。

一个创建型模式,一个行为型模式。

# 上下文类的作用

在策略模式里,上下文类是至关重要的组成部分,它主要承担着连接客户端与策略类的职责。

# 1. 封装算法选择逻辑

上下文类会把算法的选择逻辑隐藏起来,客户端只需和上下文类进行交互,而不用直接与具体的策略类打交道。客户端在使用时,只需把所需的策略传递给上下文类,具体策略的执行过程由上下文类负责管理。

# 2. 运行时策略切换

上下文类支持在程序运行期间动态地切换策略。这一特性使得系统能够根据实际情况灵活地调整算法,增强了系统的灵活性和适应性。

# 3. 解耦客户端与策略实现

通过引入上下文类,客户端和具体策略类之间的耦合度大大降低。客户端不需要了解具体策略的实现细节,只需要关注策略所提供的功能即可。这符合面向对象设计中的依赖倒置原则,提高了代码的可维护性和可扩展性。

# 4. 统一接口调用

上下文类会为所有具体策略提供一个统一的调用接口。这样一来,客户端可以以一致的方式使用不同的策略,无需关心具体策略的实现差异。

# 简单示例

下面是一个简单的 Python 示例,展示了上下文类的基本结构和作用:

# 策略接口
class Strategy:
    def execute(self):
        pass

# 具体策略A
class ConcreteStrategyA(Strategy):
    def execute(self):
        return "策略A的执行结果"

# 具体策略B
class ConcreteStrategyB(Strategy):
    def execute(self):
        return "策略B的执行结果"

# 上下文类
class Context:
    def __init__(self, strategy):
        self.strategy = strategy

    def execute_strategy(self):
        return self.strategy.execute()

# 客户端代码
context = Context(ConcreteStrategyA())
print(context.execute_strategy())  # 输出: 策略A的执行结果

context.set_strategy(ConcreteStrategyB())
print(context.execute_strategy())  # 输出: 策略B的执行结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 总结

上下文类在策略模式中扮演着关键角色,它负责管理策略的生命周期,为客户端提供统一的调用接口,并支持在运行时动态切换策略。通过这种方式,策略模式实现了算法的定义与使用分离,提高了代码的可维护性和可扩展性。

# 优点

策略模式中各种算法可以随意切换,想要替换一个算法非常简单,当需要增加新的算法时,只要创建一个新类实现相应接口即可直接使用,同时也避免了在上下文中使用条件判断语句来选择具体算法。

# 缺点

如果有大量算法,策略模式中可能会有非常多的具体算法类,并且上层模块需要了解每个策略模式的具体算法。

# 实践

支付系统策略模式实现

# 参考来源

  1. 设计模式-行为型模式,策略模式(15) - 北风之神 0509 - 博客园 (opens new window)
  2. python-patterns/patterns/behavioral/strategy.py at master · faif/python-patterns (opens new window)
  3. py-patterns/Behavioral/strategy.py at master · wklken/py-patterns (opens new window)
编辑 (opens new window)
#设计模式#策略模式
上次更新: 2025-06-26, 03:39:47
设计模式(6)——建造者模式
设计模式(8)——命令模式

← 设计模式(6)——建造者模式 设计模式(8)——命令模式→

最近更新
01
本事与投资
06-20
02
Flask 运行周期及工作原理
06-05
03
支付系统策略模式实现
06-04
更多文章>
Theme by Vdoing | Copyright © 2019-2025 IMOYAO | 别院牧志
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式