iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Python设计模式中的策略模式详解
  • 786
分享到

Python设计模式中的策略模式详解

Python策略模式Python设计模式 2023-02-08 12:02:17 786人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

目录策略模式命令模式策略模式 策略模式是一个经典的模式,简化代码。 电商领域有个功能明细可以使用“策略”模式,就是根据客户的属性或订单中的商品计算折扣。 比如

策略模式

策略模式是一个经典的模式,简化代码。

电商领域有个功能明细可以使用“策略”模式,就是根据客户的属性或订单中的商品计算折扣。

比如一个网店,指定了以下的折扣规则, 并且一个订单只能享受一个折扣:

  • 有1000积分以上的顾客,整个订单可以享受5%的折扣
  • 同一个订单中,单个商品的数量达到20个以上,单品享受10%折扣
  • 订单中不同商品的数量达到10个以上,整个订单享受7%折扣

下面是UML类图:

上下文:把一些计算委托给实现不同算法的可互换组建,他们提供服务。 在这个示例中,上下文就是Order,根据不同算法提供折扣。

策略:实现不同算法的组件共同接口。在这个示例中,Promotion的抽象类扮演这个角色。

具体策略:“策略”的子类,实现具体策略

示例,实现Order类,支持插入式折扣策略

import abc
from collections import namedtuple
from abc import abstractmethod
Customer = namedtuple('Customer', 'name fidelity')  # name:顾客名字  fidelity:忠诚度,这里用积分体现
class LineItem:
    """单品信息"""
    def __init__(self, product, quantity, price):
        self.product = product
        self.quantity = quantity
        self.price = price
    def total(self):
        return self.quantity * self.price
class Order:
    """订单信息(上下文)"""
    def __init__(self, customer, cart, promotion=None):
        self.customer = customer
        self.cart = list(cart)  # 购物车:商品列表
        self.promotion = promotion
    def total(self):
        if not hasattr(self, '__total'):  # __前缀的属性,不可继承
            self.__total = sum(item.total() for item in self.cart)
        return self.__total
    def due(self):
        """折后金额"""
        if self.promotion is None:
            discount = 0
        else:
            discount = self.promotion.discount(self)
        return self.__total - discount
    def __repr__(self):
        return '<Order total:{:.2f} due:{:.2f}>'.fORMat(self.total(), self.due())  # {:.2f}表示输出小数点,保留2位小数
class Promotion(abc.ABC):
    """策略:抽象基类"""
    @abstractmethod
    def discount(self, order):
        """返回折扣金额"""
class FidelityPromo(Promotion):
    """具体策略:有1000积分以上的顾客,整个订单可以享受5%的折扣"""
    def discount(self, order):
        return order.total() * 0.05 if order.customer.fidelity >= 1000 else 0
class BulkItemPromo(Promotion):
    """具体策略:同一个订单中,单个商品的数量达到20个以上,单品享受10%折扣"""
    def discount(self, order):
        # return order.total() * 0.1 if any(item for item in order.cart if item.quantity >= 20) else 0 理解错误为整体折扣
        discount = 0
        for item in order.cart:
            if item.quantity >= 20:
                discount += item.total() * .1
        return discount
class LargeOrderPromo(Promotion):
    """具体策略:订单中不同商品的数量达到10个以上,整个订单享受7%折扣"""
    def discount(self, order):
        return order.total() * 0.07 if len({item.product for item in order.cart}) >= 10 else 0

聊一下抽象基类:

python3.4中,声明抽象基类的最简单的方式是继承abc.ABC :class Promotion(abc.ABC):

python3.0到Python3.3中,必须在class中使用metaclass=关键字 : class Promotion(metaclass=abc.ABCMeta):

Python2中,要在 类属性中增加__metaclass__ = abc.ABCMeta

测试代码

# 两个顾客,一个积分0,一个积分1100
joe = Customer('Joe', 0)
ann = Customer('Ann', 1100)
# 有三个商品的购物车
cart = [LineItem('banana', 4, .5),
        LineItem('apple', 10, 1.5),
        LineItem('watermelon', 5, 5.0)]
# ann因为超过1000积分,获得了5%折扣
order_joe = Order(joe, cart, FidelityPromo())  #这里要FidelityPromo要加()来创建实例
print(order_joe)
order_ann = Order(ann, cart, FidelityPromo())
print(order_ann)
# 香蕉30个,苹果10个。
banana_cart = [LineItem('banana', 30, .5),
               LineItem('apple', 10, 1.5)]
# joe因为香蕉有30个,根据BulkItemPromo 香蕉优惠了1.5元
order_joe = Order(joe, banana_cart, BulkItemPromo())
print(order_joe)

打印
<Order total:42.00 due:42.00>
<Order total:42.00 due:39.90>
<Order total:30.00 due:28.50>

以上的模式中,每个具体策略都是一个类,而且只定义了一个方法:discount。此外他们的策略示例没有实例属性,看起来就像普通函数。

示例,使用函数实现折扣策略

Customer = namedtuple('Customer', 'name fidelity')  # name:顾客名字  fidelity:忠诚度,这里用积分体现
class LineItem:
    """单品信息"""
    def __init__(self, product, quantity, price):
        self.product = product
        self.quantity = quantity
        self.price = price
    def total(self):
        return self.quantity * self.price
class Order:
    """订单信息(上下文)"""
    def __init__(self, customer, cart, promotion=None):
        self.customer = customer
        self.cart = list(cart)  # 购物车:商品列表
        self.promotion = promotion
    def total(self):
        if not hasattr(self, '__total'):  # __前缀的属性,不可继承
            self.__total = sum(item.total() for item in self.cart)
        return self.__total
    def due(self):
        """折后金额"""
        if self.promotion is None:
            discount = 0
        else:
            discount = self.promotion(self)
        return self.__total - discount
    def __repr__(self):
        return '<Order total:{:.2f} due:{:.2f}>'.format(self.total(), self.due())  # {:.2f}表示输出小数点,保留2位小数
def FidelityPromo(order):
    """具体策略:有1000积分以上的顾客,整个订单可以享受5%的折扣"""
    return order.total() * 0.05 if order.customer.fidelity >= 1000 else 0
def BulkItemPromo(order):
    """具体策略:同一个订单中,单个商品的数量达到20个以上,单品享受10%折扣"""
    discount = 0
    for item in order.cart:
        if item.quantity >= 20:
            discount += item.total() * .1
    return discount
def LargeOrderPromo(order):
    """具体策略:订单中不同商品的数量达到10个以上,整个订单享受7%折扣"""
    return order.total() * 0.07 if len({item.product for item in order.cart}) >= 10 else 0
# 两个顾客,一个积分0,一个积分1100
joe = Customer('Joe', 0)
ann = Customer('Ann', 1100)
# 有三个商品的购物车
cart = [LineItem('banana', 4, .5),
        LineItem('apple', 10, 1.5),
        LineItem('watermelon', 5, 5.0)]
# ann因为超过1000积分,获得了5%折扣
order_joe = Order(joe, cart, FidelityPromo)
print(order_joe)
order_ann = Order(ann, cart, FidelityPromo)
print(order_ann)
# 香蕉30个,苹果10个。
banana_cart = [LineItem('banana', 30, .5),
               LineItem('apple', 10, 1.5)]
# joe因为香蕉有30个,根据BulkItemPromo 香蕉优惠了1.5元
order_joe = Order(joe, banana_cart, BulkItemPromo)
print(order_joe)

打印
<Order total:42.00 due:42.00>
<Order total:42.00 due:39.90>
<Order total:30.00 due:28.50>        

以上可以看到,使用函数更加简单,代码量减少。没必要在新建订单实例化新的促销对象,函数拿来即用。

选择最佳策略

要实现最佳折扣策略的自动选择,只需要一个额外的函数即可。这样就能自动找出最高的折扣。

def best_promotion(order):
    promotions = [FidelityPromo, BulkItemPromo, LargeOrderPromo]
    return max([func(order) for func in promotions])

自动找出模块中的全部策略

以上的promotions列表包含了三个策略,当再新增新的策略时,需要在这个列表中追加,使用以下写法,可以自动识别策略函数:

示例,实现了把Promo结尾的函数引用,放进promotions列表中

def best_promotion(order):
    promotions = [globals()[key] for key in list(globals().keys()) if key.endswith('Promo')]
    return max([func(order) for func in promotions])

以上实现的原理就是利用globals()内置函数:

globals()返回一个字典,表示当前的全局符号表。包含了当前所有定义的函数等。

自动找出模块中的全部策略-另一个种方案

把所有的策略函数,都放到一个模块(文件)中,然后通过import导入进来,再使用inspect模块提供的函数内省

示例,获取一个模块中的所有函数

import promotions  # 一个包含函数的模块
print(inspect.getmembers(promotions, inspect.isfunction))  # 获取一个模块中的所有函数

打印
[('BulkItemPromo', <function BulkItemPromo at 0x0342F2B8>), ('FidelityPromo', <function FidelityPromo at 0x0342F228>), ('LargeOrderPromo', <function LargeOrderPromo at 0x0342F300>)]

示例,内省promotions模块,获取所有策略函数

import promotions
promotions = [func for func_name, func in inspect.getmembers(promotions, inspect.isfunction)]
def best_promotion(order):
    return max([func(order) for func in promotions])

这样的话,以后有新的策略,只需要在promotions模块中新增对应的策略函数,就可以自动加载了,妙!

命令模式

命令模式的目的是解耦调用者(调用操作的对象)和接收者(提供实现的对象)。让他们只实现一个方法execute接口,供调用者使用,这样调用者无需了解接受者的接口,而且不同的接受者可以适应不同的Command子类。

示例,使用抽象类实现命令模式

import abc
class Receiver:
    """命令的接收者,执行命令的地方"""
    def start(self):
        print('开始执行')
    def stop(self):
        print('停止执行')
class Command(abc.ABC):
    """命令抽象类"""
    @abc.abstractmethod
    def execute(self):
        """命令对象对外只提供execute方法"""
class StartCommand(Command):
    """开始执行的命令"""
    def __init__(self, receiver):
        self.receiver = receiver
    def execute(self):
        return self.receiver.start()
class StopCommand(Command):
    """停止执行的命令"""
    def __init__(self, receiver):
        self.receiver = receiver
    def execute(self):
        return self.receiver.stop()
class Client:
    """命令的调用者"""
    def __init__(self, command):
        self.command = command
    def __call__(self, *args, **kwargs):
        return self.command.execute()
start = StartCommand(Receiver())
client = Client(start)
client()
stop = StopCommand(Receiver())
client = Client(stop)
client()

打印
开始执行
停止执行

可以不使用抽象类,直接使用一个comman()函数来代理Command示例。使用一等函数对命令模式重新审视。

到此这篇关于Python设计模式中的策略模式详解的文章就介绍到这了,更多相关Python策略模式内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Python设计模式中的策略模式详解

本文链接: https://www.lsjlt.com/news/195169.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Python设计模式中的策略模式详解
    目录策略模式命令模式策略模式 策略模式是一个经典的模式,简化代码。 电商领域有个功能明细可以使用“策略”模式,就是根据客户的属性或订单中的商品计算折扣。 比如...
    99+
    2023-02-08
    Python策略模式 Python设计模式
  • Python 中的设计模式详解之:策略模
    虽然设计模式与语言无关,但这并不意味着每一个模式都能在每一门语言中使用。《设计模式:可复用面向对象软件的基础》一书中有 23 个模式,其中有 16 个在动态语言中“不见了,或者简化了”。 1、策略模式概述 策略模式:定义一系列算法,把...
    99+
    2023-01-31
    详解 策略 模式
  • java设计模式--策略模式详解
    目录策略模式Demo代码:总结策略模式 策略模式(Strategy Pattern)属于行为型模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。用算法族分别封装起来...
    99+
    2022-11-12
  • JavaScript设计模式之策略模式详解
    什么是设计模式?为什么需要学习设计模式? 学习设计模式的目的是:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络...
    99+
    2022-11-13
  • Java设计模式之java策略模式详解
    目录为什么使用策略模式?策略模式包含角色策略模式的类图排序案例策略模式的优点策略模式的缺点适用场景源码分析策略模式的典型应用Java Comparator 中的策略模式参考文...
    99+
    2022-11-12
  • Java 设计模式中的策略模式详情
    目录策略模式的应用场景是否符合有没有必要不用策略模式例子使用策略模式策略上下文策略接口以及具体实现类Main类两种方式的不同策略模式有没有必要使用?如何避免Context类使用判断逻...
    99+
    2022-11-13
  • Java中常用的设计模式之策略模式详解
    目录优点缺点使用场景一、实现方式1、订单类型枚举类2、订单处理接口3、普通订单处理器4、秒杀订单处理器5、拼团订单处理器6、下单管理器二、测试1、引入依赖2、测试用例总结优点 1.算...
    99+
    2022-11-13
  • Java设计模式之策略模式案例详解
    目录优缺点Spring中哪里使用策略模式策略模式设计图代码案例为什么使用策略模式 答:策略模式是解决过多if-else (或者switch-case)代码块的方法之一,提高代码的可维...
    99+
    2022-11-13
  • Java设计模式之策略模式示例详解
    目录定义结构UML类图UML序列图深入理解策略模式策略和上下文的关系策略模式在JDK中的应用该策略接口有四个实现类策略模式的优点策略模式的缺点策略模式的本质在讲策略模式之前,我们先看...
    99+
    2022-11-13
  • Python设计模式中的行为型策略模式
    目录一、策略模式二、应用场景三、代码示例一、策略模式 策略模式中,首先定义了一系列不同的算法,并把它们一一封装起来,然后在策略类中,使这些算法可以相互替换。这意味着,让一个类的行为(...
    99+
    2022-11-13
  • 详解Python设计模式编程中观察者模式与策略模式的运用
    观察者模式 观察者模式:又叫发布订阅模式,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时,会通知所有观察者对象,是他们能自动更新自己。 代码结构 cla...
    99+
    2022-06-04
    模式 观察者 详解
  • java设计模式策略模式图文示例详解
    目录策略模式意图问题解决方案真实世界类比策略模式结构伪代码策略模式适合应用场景实现方式策略模式优缺点策略模式优缺点与其他模式的关系策略模式 亦称:Strategy 意图 策略模式是一...
    99+
    2022-11-13
  • Java设计模式之策略模式
    在一个收银系统中,如果普通用户、中级会员、高级会员分别对应着不同的优惠策略,常规编程就要使用一系列的判断语句,判断用户类型,这种情况下就可以使用策略模式。 一、概念理解 策略模式的概...
    99+
    2022-11-13
    Java 设计模式 策略模式
  • C#设计模式之策略模式
    策略模式 所谓策略其实就是做一件事情有很多很多的方法,比如说一个商场要搞促销,促销的方式有可能有很多:打折啊,满100返50啊、积分等等之类的。这种不同的促销方式在我们系统中表示就是...
    99+
    2022-11-13
  • javascript设计模式之策略模式
    目录一. 认识策略模式二. 具体实现和思想三. 策略模式的实际运用四. 总结一. 认识策略模式 策略模式的定义:定义一系列的算法,将他们一个个封装起来,使他们直接可以相互替换。 策略...
    99+
    2022-11-12
  • QtC++ 设计模式(四)——策略模式
    策略模式 序言理解源码 序言 还是参考的菜鸟教程,会C++的还是看C++的方式来得舒服。 . 理解 使用符合UML规范的便于理解和回忆,接口其实就是普通的基类 . 源码 strategy.h /// 策略class Strat...
    99+
    2023-08-30
    c++ 设计模式 策略模式
  • JAVA设计模式中的策略模式你了解吗
    目录策略模式策略模式是什么策略模式的使用场景策略模式实践总结策略模式 世界上本没有模式; 一些程序老鸟在长时间的编程工作总结出高效的代码写法被后世推崇; 并整理出固定的写法规范,这个...
    99+
    2022-11-13
  • 怎么理解Java设计模式的策略模式
    这篇文章主要讲解了“怎么理解Java设计模式的策略模式”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么理解Java设计模式的策略模式”吧!一、什么是策略模式策略模式定义了一系列算法,并将每...
    99+
    2023-06-25
  • 轻松掌握python设计模式之策略模式
    本文实例为大家分享了python策略模式代码,供大家参考,具体内容如下 """ 策略模式 """ import types class StrategyExample: def __init__(s...
    99+
    2022-06-04
    模式 策略 轻松
  • 深入了解Java设计模式之策略模式
    目录定义解决的问题核心要点类图溢出效用代码实现核心接口实现类-三个Context类Main方法拓展JDK源码Spring源码定义 定义了算法家族,分别封装起来,让他们之间可以相互替换...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作