Python Design Patterns: Best of "Strategy" mode Practices Code

Python Design Patterns: Best of "Strategy" mode Practices Code

Today, taking the time to read the next smooth python , python found it introduced a lot of built-in library use cases, with very elegant.

More usually used to write Python reptile, I have recently been looking at the contents of design patterns. Just inside this book includes a chapter on design patterns alone speak, speak good, specially excerpted.

Demand background of this code is commonly used in electronic business platform marketing strategy:

  1. When the user points over 1000, total order discount of 5% of the amount
  2. When the type of purchases of more than 10 kinds, order discount of 7% of total amount
  3. When the number of single commodity purchase over 20, the merchandise receive a 10% discount

Specific code as follows:

from collections import namedtuple

Customer = namedtuple('Customer', 'name fidelity')


class LineItem:

    def __init__(self, product, quantity, price):
        self.product = product
        self.quantity = quantity
        self.price = price

    def total(self):
        return self.price * self.quantity


class Order:  # the Context

    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):
        fmt = '<Order total: {:.2f} due: {:.2f}>'
        return fmt.format(self.total(), self.due())


promos = []


def promotion(promo_func):
    promos.append(promo_func)
    return promo_func


@promotion
def fidelity_promo(order):  # <3>
    """5% discount for customers with 1000 or more fidelity points"""
    return order.total() * .05 if order.customer.fidelity >= 1000 else 0


@promotion
def bulk_item_promo(order):
    """10% discount for each LineItem with 20 or more units"""
    discount = 0
    for item in order.cart:
        if item.quantity >= 20:
            discount += item.total() * .1
    return discount


@promotion
def large_order_promo(order):
    """7% discount for orders with 10 or more distinct items"""
    distinct_items = {item.product for item in order.cart}
    if len(distinct_items) >= 10:
        return order.total() * .07
    return 0


def best_promo(order):
    return max(promo(order) for promo in promos)


# # BEGIN STRATEGY_TESTS
#
#     >>> joe = Customer('John Doe', 0)  # <1>
#     >>> ann = Customer('Ann Smith', 1100)
#     >>> cart = [LineItem('banana', 4, .5),
#     ...         LineItem('apple', 10, 1.5),
#     ...         LineItem('watermellon', 5, 5.0)]
#     >>> Order(joe, cart, fidelity_promo)  # <2>
#     <Order total: 42.00 due: 42.00>
#     >>> Order(ann, cart, fidelity_promo)
#     <Order total: 42.00 due: 39.90>
#     >>> banana_cart = [LineItem('banana', 30, .5),
#     ...                LineItem('apple', 10, 1.5)]
#     >>> Order(joe, banana_cart, bulk_item_promo)  # <3>
#     <Order total: 30.00 due: 28.50>
#     >>> long_order = [LineItem(str(item_code), 1, 1.0)
#     ...               for item_code in range(10)]
#     >>> Order(joe, long_order, large_order_promo)
#     <Order total: 10.00 due: 9.30>
#     >>> Order(joe, cart, large_order_promo)
#     <Order total: 42.00 due: 42.00>
#     best promo========================================
#     >>> Order(joe, long_order, best_promo)
#     <Order total: 10.00 due: 9.30>
#     >>> Order(joe, banana_cart, best_promo)
#     <Order total: 30.00 due: 28.50>
#     >>> Order(ann, cart, best_promo)
#     <Order total: 42.00 due: 39.90>
# # END STRATEGY_TESTS
# """
# BEGIN STRATEGY

This code uses a decorator's benefit, to achieve very elegant and logical, concise code, in just 77 lines of code, to achieve a strategy mode.

However, this code is the result of three iterations, optimize after.

First Edition: ABC abstract base class used to implement

In the first version, with the ABC abstract base class to implement, the code is very long-winded, I feel like writing JAVA

# 这里只贴核心逻辑代码
from abc import ABC, abstractmethod

class Promotion(ABC):  # 策略:抽象基类

    @abstractmethod
    def discount(self, order):
        """Return discount as a positive dollar amount"""


class FidelityPromo(Promotion):  # 第一个策略
    """5% discount for customers with 1000 or more fidelity points
    拥有1000或更高积分的客户可享受5%的折扣
    """

    def discount(self, order):
        return order.total() * .05 if order.customer.fidelity >= 1000 else 0


class BulkItemPromo(Promotion):  # 第二个策略
    """10% discount for each LineItem with 20 or more units
    单件商品购买超过20个,商品总价获得10%折扣"""

    def discount(self, order):
        discount = 0
        for item in order.cart:
            if item.quantity >= 20:
                discount += item.total() * .1
        return discount


class LargeOrderPromo(Promotion):  # 第三个策略
    """7% discount for orders with 10 or more distinct items
    购买商品的各类超过10个,获得7%的折扣
    """

    def discount(self, order):
        distinct_items = {item.product for item in order.cart}
        if len(distinct_items) >= 10:
            return order.total() * .07
        return 0

Second edition: using a function implemented, more flat, reusable

def fidelity_promo(order):
    """5% discount for customers with 1000 or more fidelity points"""
    return order.total() * .05 if order.customer.fidelity >= 1000 else 0


def bulk_item_promo(order):
    """10% discount for each LineItem with 20 or more units"""
    discount = 0
    for item in order.cart:
        if item.quantity >= 20:
            discount += item.total() * .1
    return discount


def large_order_promo(order):
    """7% discount for orders with 10 or more distinct items"""
    distinct_items = {item.product for item in order.cart}
    if len(distinct_items) >= 10:
        return order.total() * .07
    return 0

# BEGIN STRATEGY_BEST

promos = [fidelity_promo, bulk_item_promo, large_order_promo]  # <1>

def best_promo(order):  # <2>
    """Select best discount available
    """
    return max(promo(order) for promo in promos)  # <3>

Well some of the major changes is an abstract class removed, replaced function to use to achieve a more flattened. And not so much the object is instantiated.

Third Edition: The promotional package to a logic module which

import inspect
import promotions

# 把上面那3个促销策略代码挪到promotions模块中
# 这个模块里只有这3个函数
promos = [func for name, func in inspect.getmembers(promotions, inspect.isfunction)]

def best_promo(order):
    """Select best discount available
    """
    return max(promo(order) for promo in promos)

In fact, the third edition has been very elegant, all the promotional logic all packaged into promotions in the future to add a new marketing strategy, just need to change the promotionsfile inside the code just fine.

References:

  1. Sample code for Chapter 6 - "Design patterns with first class functions"

Guess you like

Origin www.cnblogs.com/seozed/p/11888844.html