趣谈设计模式之策略模式-比特咖啡给你一杯满满的情绪价值,让您在数字世界里”畅饮“

策略模式

在程序运行时动态的选择不同的算法策略或者行为,是一种行为型设计模式。策略对象之间是独立的,没有共享状态,客户端自由选择不同的策略对象。

策略模式的角色
  • 策略接口类
  • 具体策略类
  • 上下文对象: 持有一个或多个策略对象,将具体的任务委托给其中的某个策略对象完成
策略模式的优缺点

优点:

  • 提高代码的可维护性和可扩展性,满足开闭原则
  • 避免条件判断:通过策略模式,可以避免在代码中使用大量的条件判断语句,使代码更加简洁和易于维护
  • 具有一定的安全性,将算法封装起来,对于外部调用者只关注不同的策略的作用,无需关心策略的具体实现

缺点:

  • 复杂度不可控,随着策略类的增多,客户端需要知道所有的策略类,并显式的选择不同的策略对象,会使代码变得复杂。
策略模式的应用场景举例
  • 满减、返现、促销等活动
  • 游戏的情节设置,打斗场景等
python 复制代码
# 定义支付策略接口类
class PaymentStrategy(ABC):

    @abstractmethod
    def pay(self, money):
        pass


# 定义具体支付策略类
class AliPayStrategy(PaymentStrategy):

    def pay(self, money):
        print(f"使用支付宝支付{money}元。")


class WechatPayStrategy(PaymentStrategy):

    def pay(self, money):
        print(f"使用微信支付{money}元。")


class PaymentContext:

    def __init__(self, strategy: PaymentStrategy):
        self.strategy = strategy

    def set_strategy(self, strategy: PaymentStrategy):
        self.strategy = strategy

    def payment(self, money):
        self.strategy.pay(money)


# 支付终端
def payment_client():
    # 创建支付上下文对象,并初始化支付策略类
    alipay = AliPayStrategy()
    wechatpay = WechatPayStrategy()

    context = PaymentContext(alipay)
    context.payment(100)

    context.set_strategy(wechatpay)
    context.payment(200)
策略模式虚构故事

比特咖啡老板姬比特:幸瑞,我们比特数字咖啡最最最最重要的是盈利,我设计了几种套餐方案,给你2周时间把它实现了,季度套餐需要按照自然月,而且比如购买10个月的,那就适用的套餐方案只能是,月度、季度,不能使用年度。

包月2.9元:月月新鲜

包季6.9元:季度优惠

包年19.9元:年度超值

牛马程序员幸瑞:好的,我准备把包月、包季、包年的价格策略分别做成不同的"策略类"。用户选哪个套餐,我们就用哪个策略来计算费用。这样不仅灵活,还能随时添加新的套餐,完全不影响现有系统!

姬比特:听起来不错!那具体怎么实现呢?

幸瑞:比如说,包月2.9元,包季6.9元,包年19.9元。我们可以把这些策略写成代码,让顾客根据自己的需求选择。而且,通过策略模式,我们还可以动态调整价格,比如搞个"半年特惠",只需要加一个新的策略类就行了!

且看幸瑞的实现代码:

python 复制代码
class PricingStrategy:
    def calculate_cost(self, months):
        pass


# 月包
class MonthlyStrategy(PricingStrategy):
    def calculate_cost(self, months):
        return 2.9 * months


# 季包
class QuarterlyStrategy(PricingStrategy):
    def calculate_cost(self, months):
        # 每季度3个月
        quarters = months // 3
        remainder = months % 3
        return 6.9 * quarters + 2.9 * remainder


# 年包
class AnnualStrategy(PricingStrategy):
    def calculate_cost(self, months):
        # 每年12个月
        years = months // 12
        remainder = months % 12
        return 19.9 * years + 2.9 * remainder


# 上下文对象
class CoffeePricingContext:
    def __init__(self, strategy):
        self.strategy = strategy

    def set_strategy(self, strategy):
        self.strategy = strategy

    def get_total_cost(self, months):
        return self.strategy.calculate_cost(months)


# 客户端-实现动态切换,以月为基本单位,给与用户最大优惠
# 创建具体的策略对象
monthly_strategy = MonthlyStrategy()
quarterly_strategy = QuarterlyStrategy()
annual_strategy = AnnualStrategy()

# 创建咖啡定价上下文,并设置初始策略
pricing_context = CoffeePricingContext(monthly_strategy)

payment_plan = [quarterly_strategy, annual_strategy]

# 各套餐价格
cost = []

# 假设用户选择10个月
cost.append(pricing_context.get_total_cost(10))

for plan in payment_plan:
    pricing_context.set_strategy(plan)
    cost.append(pricing_context.get_total_cost(10))

minimum_cost = min(cost)
print(f"您的最优价格: {minimum_cost}")

比特咖啡老板姬比特:对了,幸瑞,你刚提到了半年特惠,要不把半年特惠的套餐也加上去

幸瑞:可以是可以,这个是新增的需求,之前说的2周时间不够,得再加2天

姬比特:什么?2天!这不就是多写一个策略类吗? 我看了前面写的代码,应该也就2min吧就完成了吧,幸瑞啊别把我当傻子,你最好老实点,给你2周时间剩下的时间够你摸鱼了。

瑞幸:(略带尴尬...)老板,您不知道,策略模式虽然灵活,但新增一个策略可不是简单的复制粘贴。我得确保新的策略类能够完美融入现有的系统,不会影响其他功能的正常运行 balabala...

姬比特:好了,别说了,还是2周时间,你要是搞不定,我可就动手了...

幸瑞:动手? 你要干嘛?

姬比特:当然是我亲自上手写代码了

幸瑞:放心老板,一定按时完成任务。

python 复制代码
# 超值半年特惠套餐
class HalfYearlyStrategy(PricingStrategy):

    def calculate_cost(self, months):
        # 每半年6个月
        half_years = months // 6
        remainder = months % 6
        return (19.9 / 2) * half_years + 2.9 * remainder  # 假设半年价格为9.95元

在没有半年特惠套餐之前,购买10个月最优化价格是 6.9 * 3 + 2.9 = 23.6
增加半年特惠套餐之后,购买10个月最优化价格 9.95 * 1 + 2.9 * 4 ~= 21.55

总之新增的半年特惠套餐让利了用户。

比特咖啡系列故事的传送门

相关推荐
杨充几秒前
6.设计原则的全景图
设计模式·开源·全栈
杨充2 分钟前
2.面向对象的特性
设计模式
杨充3 分钟前
7.SOLID原则案例汇
设计模式·开源·全栈
杨充3 分钟前
8.反模式与坏味道
设计模式·开源·代码规范
杨充12 分钟前
3.接口vs抽象类比较
设计模式
咖啡八杯3 小时前
文法、BNF与AST
java·设计模式·解释器模式·ast·文法
咖啡八杯12 小时前
GoF设计模式——解释器模式
java·后端·spring·设计模式
大数据新鸟15 小时前
设计模式四大基本原则
设计模式
南一Nanyi20 小时前
依赖注入和控制反转
前端·设计模式·nestjs