什么是策略模式?

策略模式是一种行为型设计模式,它的核心目的是将一组算法封装起来,让它们可以互相替换,并使算法的变化独立于使用它的客户端代码。

通俗解释:
  • 假设你有一个应用程序需要根据用户的不同需求,动态选择不同的行为,比如:
    • 不同的付款方式(如支付宝、微信、信用卡支付)。
    • 不同的排序算法(如快速排序、冒泡排序)。
    • 不同的促销策略(如满减、打折、返现)。

通过策略模式,你可以将这些算法(或行为)抽象出来,每种算法用一个类来实现,然后在运行时动态选择需要的算法,而无需修改客户端代码。


策略模式的结构

UML类图
             +----------------+
             |   Context      |   // 上下文环境类
             +----------------+
                     |
                     |
             +----------------+
             |   Strategy     |   // 策略抽象类
             +----------------+
                     ^
                     |
     +----------------------------------+
     |               |                  |
+--------------+  +--------------+  +--------------+
| ConcreteStrategyA|  ConcreteStrategyB|  ConcreteStrategyC|
|     具体策略A    |     具体策略B    |     具体策略C    |
+--------------+  +--------------+  +--------------+
组成
  1. Strategy(策略接口):
    定义所有策略的统一接口,使得不同策略可以互相替换。

  2. ConcreteStrategy(具体策略):
    实现具体的算法或行为。

  3. Context(上下文环境类):
    持有一个Strategy对象的引用,调用策略对象的方法完成具体的任务。

  4. 客户端(Client):
    负责选择并设置具体的策略,或者将策略传递给上下文环境类。


策略模式的核心思想

策略模式的核心思想是分离算法的定义和使用。客户端代码不需要知道具体的算法细节,只需要知道策略接口。这样可以通过不同的策略实现类,在运行时灵活切换行为,而不用修改客户端代码。


策略模式的优点和缺点

优点
  1. 开闭原则:可以方便地增加新的策略,而无需修改已有代码。
  2. 减少代码耦合:将算法和使用算法的代码解耦,便于维护。
  3. 提高代码灵活性:可以在运行时动态选择不同的算法。
缺点
  1. 类的数量增加:每个策略都需要定义一个类,可能会导致类的数量较多。
  2. 客户端必须知道所有的策略:客户端需要清楚有哪些策略可以选择。

案例:商品价格促销系统

需求描述

我们需要设计一个商品促销系统,支持以下促销策略:

  1. 正常价格(无折扣)
  2. 满减(满100减20)
  3. 打折(7折优惠)
目标
  • 使用策略模式实现上述需求,能够在运行时动态选择促销策略。
  • 输出信息使用中文以便理解。

代码实现

#include <iostream>
#include <memory>

// 策略接口:定义计算价格的统一接口
class PricingStrategy {
public:
    virtual double calculatePrice(double originalPrice) const = 0; // 定义统一的价格计算方法
    virtual ~PricingStrategy() = default;
};

// 具体策略1:正常价格(无折扣)
class NormalPricing : public PricingStrategy {
public:
    double calculatePrice(double originalPrice) const override {
        std::cout << "正常价格,无折扣。" << std::endl;
        return originalPrice;
    }
};

// 具体策略2:满减(满100减20)
class FullReductionPricing : public PricingStrategy {
public:
    double calculatePrice(double originalPrice) const override {
        if (originalPrice >= 100) {
            std::cout << "满减促销:满100减20。" << std::endl;
            return originalPrice - 20;
        } else {
            std::cout << "未达到满减条件,原价结算。" << std::endl;
            return originalPrice;
        }
    }
};

// 具体策略3:打折(7折优惠)
class DiscountPricing : public PricingStrategy {
public:
    double calculatePrice(double originalPrice) const override {
        std::cout << "打折促销:7折优惠。" << std::endl;
        return originalPrice * 0.7;
    }
};

// 上下文环境类:使用促销策略来计算价格
class ShoppingCart {
private:
    std::shared_ptr<PricingStrategy> strategy; // 持有一个策略对象的引用

public:
    // 设置策略
    void setPricingStrategy(std::shared_ptr<PricingStrategy> newStrategy) {
        strategy = newStrategy;
    }

    // 计算价格
    double calculateTotal(double originalPrice) const {
        if (strategy) {
            return strategy->calculatePrice(originalPrice);
        } else {
            std::cerr << "错误:未设置促销策略!" << std::endl;
            return originalPrice;
        }
    }
};

// 客户端代码
int main() {
    ShoppingCart cart; // 创建购物车

    // 原价
    double originalPrice = 150.0;

    // 使用正常价格策略
    cart.setPricingStrategy(std::make_shared<NormalPricing>());
    std::cout << "最终价格: " << cart.calculateTotal(originalPrice) << " 元" << std::endl;

    // 使用满减策略
    cart.setPricingStrategy(std::make_shared<FullReductionPricing>());
    std::cout << "最终价格: " << cart.calculateTotal(originalPrice) << " 元" << std::endl;

    // 使用打折策略
    cart.setPricingStrategy(std::make_shared<DiscountPricing>());
    std::cout << "最终价格: " << cart.calculateTotal(originalPrice) << " 元" << std::endl;

    return 0;
}

运行结果

正常价格,无折扣。
最终价格: 150 元
满减促销:满100减20。
最终价格: 130 元
打折促销:7折优惠。
最终价格: 105 元

代码讲解

1. 策略接口(PricingStrategy)
class PricingStrategy {
public:
    virtual double calculatePrice(double originalPrice) const = 0;
    virtual ~PricingStrategy() = default;
};
  • 定义了一个统一的价格计算接口。
  • 所有的具体策略类都需要实现calculatePrice方法。

2. 具体策略类
class NormalPricing : public PricingStrategy {
public:
    double calculatePrice(double originalPrice) const override {
        std::cout << "正常价格,无折扣。" << std::endl;
        return originalPrice;
    }
};
  • NormalPricing:实现了正常价格策略,返回原价。
  • FullReductionPricing:实现了满减策略,满足条件则减去20元。
  • DiscountPricing:实现了7折优惠策略。

每个具体策略类只实现自己的算法,彼此独立。


3. 上下文环境类(ShoppingCart)
class ShoppingCart {
private:
    std::shared_ptr<PricingStrategy> strategy;

public:
    void setPricingStrategy(std::shared_ptr<PricingStrategy> newStrategy) {
        strategy = newStrategy;
    }

    double calculateTotal(double originalPrice) const {
        if (strategy) {
            return strategy->calculatePrice(originalPrice);
        } else {
            std::cerr << "错误:未设置促销策略!" << std::endl;
            return originalPrice;
        }
    }
};
  • 上下文类ShoppingCart持有一个策略对象的引用,通过setPricingStrategy方法动态设置策略。
  • calculateTotal方法调用当前策略的calculatePrice方法完成价格计算。

4. 客户端代码
cart.setPricingStrategy(std::make_shared<NormalPricing>());
std::cout << "最终价格: " << cart.calculateTotal(originalPrice) << " 元" << std::endl;
  • 客户端通过setPricingStrategy方法动态选择策略。
  • 可以在运行时切换不同的策略,灵活应对不同的促销规则。

策略模式的优缺点

优点
  1. 开闭原则:可以轻松添加新的策略,而无需修改现有代码。
  2. 灵活扩展:通过动态设置策略,可以灵活切换行为。
  3. 代码解耦:将算法的实现与算法的使用分离,提高代码的可维护性。
缺点
  1. 策略类增多:每个策略需要定义一个类,当策略较多时,会增加类的数量。
  2. 客户端必须了解策略:客户端需要知道有哪些策略可以选择。

总结

策略模式是一种非常灵活的设计模式,通过将算法封装为独立的类,使得算法可以独立扩展和替换。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐