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

策略模式

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

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

优点:

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

缺点:

  • 复杂度不可控,随着策略类的增多,客户端需要知道所有的策略类,并显式的选择不同的策略对象,会使代码变得复杂。
策略模式的应用场景举例
  • 满减、返现、促销等活动
  • 游戏的情节设置,打斗场景等
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

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

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

相关推荐
写bug写bug1 小时前
你真的会用枚举吗
java·后端·设计模式
华仔啊6 小时前
别学23种了!Java项目中最常用的6个设计模式,附案例
java·后端·设计模式
Keya9 小时前
MacOS端口被占用的解决方法
前端·后端·设计模式
已读不回14310 小时前
设计模式-单例模式
前端·设计模式
long3161 天前
构建者设计模式 Builder
java·后端·学习·设计模式
一乐小哥1 天前
从 JDK 到 Spring,单例模式在源码中的实战用法
后端·设计模式
付春员2 天前
23种设计模式
设计模式
Zyy~2 天前
《设计模式》工厂方法模式
设计模式·工厂方法模式
克拉克盖博2 天前
chapter03_Bean的实例化与策略模式
java·spring·策略模式