策略模式 (Strategy)
策略模式 是一种行为型设计模式,它定义了一系列算法,并将每种算法封装到独立的类中,使得它们可以相互替换。策略模式让算法的变化不会影响使用算法的客户端。
意图
- 将算法的定义与使用分离。
- 通过封装和组合的方式,使得算法可以灵活替换。
使用场景
-
系统需要动态选择算法:
- 需要在运行时根据条件选择不同的算法实现。
-
避免使用大量条件语句:
- 如果系统中有大量的
if-else
或switch
语句,可以使用策略模式将这些条件逻辑封装为独立的策略类。
- 如果系统中有大量的
-
算法需要灵活扩展:
- 新增算法时无需修改客户端代码,只需实现新的策略类即可。
参与者角色
-
上下文类 (Context)
- 持有对策略对象的引用,并通过策略接口调用具体策略的方法。
-
策略接口 (Strategy)
- 定义了所有具体策略的公共接口。
-
具体策略类 (ConcreteStrategy)
- 实现策略接口,封装具体的算法逻辑。
示例代码
以下代码展示了策略模式的实现,用于计算不同折扣策略下的商品价格。
cpp
#include <iostream>
#include <memory>
// 策略接口:折扣策略
class DiscountStrategy {
public:
virtual ~DiscountStrategy() = default;
virtual double calculatePrice(double originalPrice) const = 0; // 计算折后价格
};
// 具体策略类:无折扣
class NoDiscount : public DiscountStrategy {
public:
double calculatePrice(double originalPrice) const override {
return originalPrice; // 无折扣,返回原价
}
};
// 具体策略类:百分比折扣
class PercentageDiscount : public DiscountStrategy {
private:
double discountRate; // 折扣率
public:
PercentageDiscount(double rate) : discountRate(rate) {}
double calculatePrice(double originalPrice) const override {
return originalPrice * (1 - discountRate); // 按折扣率计算
}
};
// 具体策略类:固定金额折扣
class FixedAmountDiscount : public DiscountStrategy {
private:
double discountAmount; // 折扣金额
public:
FixedAmountDiscount(double amount) : discountAmount(amount) {}
double calculatePrice(double originalPrice) const override {
return (originalPrice > discountAmount) ? (originalPrice - discountAmount) : 0; // 不低于0元
}
};
// 上下文类:价格计算器
class PriceCalculator {
private:
std::unique_ptr<DiscountStrategy> strategy; // 策略对象
public:
void setStrategy(std::unique_ptr<DiscountStrategy> newStrategy) {
strategy = std::move(newStrategy); // 动态设置策略
}
double calculate(double originalPrice) const {
if (strategy) {
return strategy->calculatePrice(originalPrice); // 调用策略计算价格
} else {
throw std::runtime_error("No strategy set!");
}
}
};
// 客户端代码
int main() {
PriceCalculator calculator;
// 设置无折扣策略
calculator.setStrategy(std::make_unique<NoDiscount>());
std::cout << "Original Price: $100, Final Price: $" << calculator.calculate(100) << std::endl;
// 设置百分比折扣策略
calculator.setStrategy(std::make_unique<PercentageDiscount>(0.2)); // 20% 折扣
std::cout << "Original Price: $100, Final Price: $" << calculator.calculate(100) << std::endl;
// 设置固定金额折扣策略
calculator.setStrategy(std::make_unique<FixedAmountDiscount>(30)); // 减30元
std::cout << "Original Price: $100, Final Price: $" << calculator.calculate(100) << std::endl;
return 0;
}
代码解析
1. 策略接口 (DiscountStrategy)
- 定义了计算折扣价格的接口:
cpp
class DiscountStrategy {
public:
virtual ~DiscountStrategy() = default;
virtual double calculatePrice(double originalPrice) const = 0;
};
2. 具体策略类
- 每个具体策略类实现了
DiscountStrategy
接口,封装了具体的算法逻辑:
cpp
class PercentageDiscount : public DiscountStrategy {
private:
double discountRate;
public:
PercentageDiscount(double rate) : discountRate(rate) {}
double calculatePrice(double originalPrice) const override {
return originalPrice * (1 - discountRate);
}
};
3. 上下文类 (PriceCalculator)
PriceCalculator
类持有对策略对象的引用,负责调用策略的calculatePrice
方法:
cpp
class PriceCalculator {
private:
std::unique_ptr<DiscountStrategy> strategy;
public:
void setStrategy(std::unique_ptr<DiscountStrategy> newStrategy) {
strategy = std::move(newStrategy);
}
double calculate(double originalPrice) const {
if (strategy) {
return strategy->calculatePrice(originalPrice);
} else {
throw std::runtime_error("No strategy set!");
}
}
};
4. 客户端
- 客户端通过上下文类设置不同的策略对象,实现动态切换算法:
cpp
calculator.setStrategy(std::make_unique<NoDiscount>());
std::cout << "Final Price: $" << calculator.calculate(100) << std::endl;
calculator.setStrategy(std::make_unique<PercentageDiscount>(0.2));
std::cout << "Final Price: $" << calculator.calculate(100) << std::endl;
优缺点
优点
- 算法独立 :
- 每种算法封装在独立的类中,易于扩展和维护。
- 动态切换 :
- 可以在运行时灵活替换算法,而无需修改客户端代码。
- 消除条件语句 :
- 避免了大量的
if-else
或switch
语句。
- 避免了大量的
缺点
- 增加系统复杂性 :
- 每种策略需要定义一个类,可能增加系统的类数量。
- 客户端必须了解策略 :
- 客户端需要知道有哪些策略可用,并显式设置策略。
适用场景
-
系统中有多种算法可以选择:
- 如排序算法、折扣计算、加密算法等。
-
需要动态切换算法:
- 在运行时根据条件选择最优的算法。
-
消除条件判断:
- 当系统中有大量的条件分支时,可以使用策略模式将分支逻辑替换为独立的策略类。
总结
策略模式通过将算法封装为独立的类,使得算法可以灵活切换并独立扩展。它是一种非常灵活的设计模式,特别适用于需要动态选择算法的场景。