最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python設(shè)計模式中的策略模式詳解

 更新時間:2023年02月08日 11:45:14   作者:lijiachang8  
策略模式屬于Python-設(shè)計模式中行為模式之一,該模式定義了一系列算法,并將每個算法封裝起來,使它們可以相互替換。本文將通過示例詳細講解這一模式,需要的可以參考一下

策略模式

策略模式是一個經(jīng)典的模式,簡化代碼。

電商領(lǐng)域有個功能明細可以使用“策略”模式,就是根據(jù)客戶的屬性或訂單中的商品計算折扣。

比如一個網(wǎng)店,指定了以下的折扣規(guī)則, 并且一個訂單只能享受一個折扣:

  • 有1000積分以上的顧客,整個訂單可以享受5%的折扣
  • 同一個訂單中,單個商品的數(shù)量達到20個以上,單品享受10%折扣
  • 訂單中不同商品的數(shù)量達到10個以上,整個訂單享受7%折扣

下面是UML類圖:

上下文:把一些計算委托給實現(xiàn)不同算法的可互換組建,他們提供服務(wù)。 在這個示例中,上下文就是Order,根據(jù)不同算法提供折扣。

策略:實現(xiàn)不同算法的組件共同接口。在這個示例中,Promotion的抽象類扮演這個角色。

具體策略:“策略”的子類,實現(xiàn)具體策略

示例,實現(xiàn)Order類,支持插入式折扣策略

import abc
from collections import namedtuple
from abc import abstractmethod
Customer = namedtuple('Customer', 'name fidelity')  # name:顧客名字  fidelity:忠誠度,這里用積分體現(xiàn)
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}表示輸出小數(shù)點,保留2位小數(shù)
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):
    """具體策略:同一個訂單中,單個商品的數(shù)量達到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):
    """具體策略:訂單中不同商品的數(shù)量達到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=關(guān)鍵字 : 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要加()來創(chuàng)建實例
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個,根據(jù)BulkItemPromo 香蕉優(yōu)惠了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。此外他們的策略示例沒有實例屬性,看起來就像普通函數(shù)。

示例,使用函數(shù)實現(xiàn)折扣策略

Customer = namedtuple('Customer', 'name fidelity')  # name:顧客名字  fidelity:忠誠度,這里用積分體現(xiàn)
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}表示輸出小數(shù)點,保留2位小數(shù)
def FidelityPromo(order):
    """具體策略:有1000積分以上的顧客,整個訂單可以享受5%的折扣"""
    return order.total() * 0.05 if order.customer.fidelity >= 1000 else 0
def BulkItemPromo(order):
    """具體策略:同一個訂單中,單個商品的數(shù)量達到20個以上,單品享受10%折扣"""
    discount = 0
    for item in order.cart:
        if item.quantity >= 20:
            discount += item.total() * .1
    return discount
def LargeOrderPromo(order):
    """具體策略:訂單中不同商品的數(shù)量達到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個,根據(jù)BulkItemPromo 香蕉優(yōu)惠了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>        

以上可以看到,使用函數(shù)更加簡單,代碼量減少。沒必要在新建訂單實例化新的促銷對象,函數(shù)拿來即用。

選擇最佳策略

要實現(xiàn)最佳折扣策略的自動選擇,只需要一個額外的函數(shù)即可。這樣就能自動找出最高的折扣。

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

自動找出模塊中的全部策略

以上的promotions列表包含了三個策略,當再新增新的策略時,需要在這個列表中追加,使用以下寫法,可以自動識別策略函數(shù):

示例,實現(xiàn)了把Promo結(jié)尾的函數(shù)引用,放進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])

以上實現(xiàn)的原理就是利用globals()內(nèi)置函數(shù):

globals()返回一個字典,表示當前的全局符號表。包含了當前所有定義的函數(shù)等。

自動找出模塊中的全部策略-另一個種方案

把所有的策略函數(shù),都放到一個模塊(文件)中,然后通過import導入進來,再使用inspect模塊提供的函數(shù)內(nèi)省

示例,獲取一個模塊中的所有函數(shù)

import promotions  # 一個包含函數(shù)的模塊
print(inspect.getmembers(promotions, inspect.isfunction))  # 獲取一個模塊中的所有函數(shù)

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

示例,內(nèi)省promotions模塊,獲取所有策略函數(shù)

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模塊中新增對應(yīng)的策略函數(shù),就可以自動加載了,妙!

命令模式

命令模式的目的是解耦調(diào)用者(調(diào)用操作的對象)和接收者(提供實現(xiàn)的對象)。讓他們只實現(xiàn)一個方法execute接口,供調(diào)用者使用,這樣調(diào)用者無需了解接受者的接口,而且不同的接受者可以適應(yīng)不同的Command子類。

示例,使用抽象類實現(xiàn)命令模式

import abc
class Receiver:
    """命令的接收者,執(zhí)行命令的地方"""
    def start(self):
        print('開始執(zhí)行')
    def stop(self):
        print('停止執(zhí)行')
class Command(abc.ABC):
    """命令抽象類"""
    @abc.abstractmethod
    def execute(self):
        """命令對象對外只提供execute方法"""
class StartCommand(Command):
    """開始執(zhí)行的命令"""
    def __init__(self, receiver):
        self.receiver = receiver
    def execute(self):
        return self.receiver.start()
class StopCommand(Command):
    """停止執(zhí)行的命令"""
    def __init__(self, receiver):
        self.receiver = receiver
    def execute(self):
        return self.receiver.stop()
class Client:
    """命令的調(diào)用者"""
    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()

打印
開始執(zhí)行
停止執(zhí)行

可以不使用抽象類,直接使用一個comman()函數(shù)來代理Command示例。使用一等函數(shù)對命令模式重新審視。

到此這篇關(guān)于Python設(shè)計模式中的策略模式詳解的文章就介紹到這了,更多相關(guān)Python策略模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python中PyExecJS(執(zhí)行JS代碼庫)的具體使用

    Python中PyExecJS(執(zhí)行JS代碼庫)的具體使用

    pyexecjs是一個用Python來執(zhí)行JavaScript代碼的工具庫,本文主要介紹了Python中PyExecJS(執(zhí)行JS代碼庫)的具體使用,具有一定的參考價值,感興趣的可以了解一下
    2024-02-02
  • Python編程使用PyQt5庫實現(xiàn)動態(tài)水波進度條示例

    Python編程使用PyQt5庫實現(xiàn)動態(tài)水波進度條示例

    這篇文章主要介紹了Python編程使用PyQt5庫實現(xiàn)動態(tài)水波進度條的示例代碼解析,有需要的朋友可以借鑒參考下希望能夠有所幫助,祝大家多多進步早日升職加薪
    2021-10-10
  • xshell會話批量遷移到mobaxterm的工具(python小工具)

    xshell會話批量遷移到mobaxterm的工具(python小工具)

    這篇文章主要介紹了xshell會話批量遷移到mobaxterm的工具,使用方法也超級簡單,本文通過python代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-12-12
  • Python extract及contains方法代碼實例

    Python extract及contains方法代碼實例

    這篇文章主要介紹了Python extract及contains方法代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-09-09
  • Python中連接字符串的7種方法小結(jié)

    Python中連接字符串的7種方法小結(jié)

    Python?提供了將一個或多個字符串連接在一起的多種方法,本文主要介紹了Python中連接字符串的7種方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-06-06
  • python學生信息管理系統(tǒng)實現(xiàn)代碼

    python學生信息管理系統(tǒng)實現(xiàn)代碼

    這篇文章主要為大家詳細介紹了python學生信息管理系統(tǒng)的實現(xiàn)代碼,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • Django 權(quán)限認證(根據(jù)不同的用戶,設(shè)置不同的顯示和訪問權(quán)限)

    Django 權(quán)限認證(根據(jù)不同的用戶,設(shè)置不同的顯示和訪問權(quán)限)

    這篇文章主要介紹了Django 權(quán)限認證(根據(jù)不同的用戶,設(shè)置不同的顯示和訪問權(quán)限),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-07-07
  • Python GUI之如何使用tkinter控件

    Python GUI之如何使用tkinter控件

    今天帶大家學習Python GUI的相關(guān)知識,文中對如何使用tkinter控件作了非常詳細的介紹及代碼示例,對正在學習python的小伙伴們有很好的幫助,需要的朋友可以參考下
    2021-05-05
  • Python中type的構(gòu)造函數(shù)參數(shù)含義說明

    Python中type的構(gòu)造函數(shù)參數(shù)含義說明

    這篇文章主要介紹了Python中type的構(gòu)造函數(shù)參數(shù)含義說明,本文用一個編碼實例解釋Python type的參數(shù)的作用和含義,需要的朋友可以參考下
    2015-06-06
  • Python標準庫之collections包的使用教程

    Python標準庫之collections包的使用教程

    這篇文章主要給大家介紹了Python標準庫之collections包的使用教程,詳細介紹了collections中多個集合類的使用方法,相信對大家具有一定的參考價值,需要的朋友們下面隨小編一起來學習學習吧。
    2017-04-04

最新評論

宜兰县| 永康市| 汉寿县| 高密市| 西乌| 汕头市| 陆川县| 镇原县| 乐平市| 抚宁县| 定安县| 廉江市| 和林格尔县| 南昌县| 济源市| 台前县| 五台县| 江油市| 两当县| 交城县| 岳阳县| 中牟县| 静宁县| 香港 | 邯郸市| 兴国县| 临高县| 扎赉特旗| 昭苏县| 舟曲县| 秀山| 滕州市| 武平县| 五家渠市| 来凤县| 德格县| 黄大仙区| 岑溪市| 崇左市| 阿鲁科尔沁旗| 抚顺县|