在软件开发中,我们经常遇到需要根据不同的条件或算法执行不同操作的情况。如果简单地使用大量的 if-else 语句,代码将变得难以维护和扩展。今天我们来精读 C++20 的行为型设计模式之一——策略模式,学习如何通过封装不同的算法策略,让代码更加灵活和可维护。类似于 Nginx 根据请求的 URI 选择不同的 location 块来处理请求,策略模式也是根据条件选择不同的策略来执行。区别在于 Nginx 是通过配置文件,而策略模式是通过代码来选择。
策略模式的核心思想
策略模式的核心思想是将算法与使用算法的代码分离。它定义了一组算法,并将每个算法封装到独立的策略类中。客户端可以根据需要选择不同的策略,而无需修改算法本身。
以下是策略模式的几个关键角色:
- Context(上下文): 包含对策略对象的引用,负责维护和使用策略。
- Strategy(策略接口): 定义所有策略类需要实现的接口,通常是一个抽象类或接口。
- ConcreteStrategy(具体策略): 实现策略接口的具体算法。
C++20 中的策略模式实现
下面我们通过一个简单的例子来说明如何在 C++20 中实现策略模式。假设我们需要根据不同的支付方式进行支付。
#include <iostream>
#include <string>
#include <memory>
// 策略接口
class PaymentStrategy {
public:
virtual void pay(int amount) = 0;
virtual ~PaymentStrategy() = default; // 记得添加虚析构函数
};
// 具体策略:信用卡支付
class CreditCardPayment : public PaymentStrategy {
private:
std::string cardNumber;
std::string expiryDate;
std::string cvv;
public:
CreditCardPayment(std::string cardNumber, std::string expiryDate, std::string cvv) :
cardNumber(cardNumber), expiryDate(expiryDate), cvv(cvv) {}
void pay(int amount) override {
std::cout << "Paid " << amount << " using Credit Card" << std::endl;
// 在实际应用中,这里会调用信用卡支付的 API
}
};
// 具体策略:支付宝支付
class AlipayPayment : public PaymentStrategy {
private:
std::string account;
public:
AlipayPayment(std::string account) : account(account) {}
void pay(int amount) override {
std::cout << "Paid " << amount << " using Alipay" << std::endl;
// 在实际应用中,这里会调用支付宝支付的 API
}
};
// 上下文
class ShoppingCart {
private:
std::unique_ptr<PaymentStrategy> paymentStrategy; // 使用智能指针管理策略对象
public:
void setPaymentStrategy(std::unique_ptr<PaymentStrategy> strategy) {
paymentStrategy = std::move(strategy);
}
void checkout(int amount) {
if (paymentStrategy) {
paymentStrategy->pay(amount);
} else {
std::cout << "No payment strategy selected!" << std::endl;
}
}
};
int main() {
ShoppingCart cart;
// 使用信用卡支付
cart.setPaymentStrategy(std::make_unique<CreditCardPayment>("1234-5678-9012-3456", "12/24", "123"));
cart.checkout(100);
// 使用支付宝支付
cart.setPaymentStrategy(std::make_unique<AlipayPayment>("example@alipay.com"));
cart.checkout(50);
return 0;
}
在这个例子中,PaymentStrategy 是策略接口,CreditCardPayment 和 AlipayPayment 是具体策略,ShoppingCart 是上下文。客户端可以通过 setPaymentStrategy 方法动态地设置支付策略。这种方式比使用 if-else 语句判断支付方式更加灵活和可扩展。
实战避坑经验总结
- 避免内存泄漏: 使用智能指针(如
std::unique_ptr)来管理策略对象,确保在不再需要策略对象时能够自动释放内存。 - 策略选择的灵活性: 可以通过配置文件(类似于 Nginx 的配置文件)或工厂模式来动态地选择策略。如果需要动态加载策略,可以考虑使用插件化的方式。
- 关注性能: 如果策略的创建和销毁代价较高,可以考虑使用对象池来复用策略对象。尤其在高并发场景下,例如处理高并发连接数的服务器,对象池能够显著提升性能。
- 策略的参数化: 考虑如何将参数传递给策略对象。可以使用构造函数、setter 方法或策略接口中的参数来传递参数。
- 组合策略: 可以将多个策略组合起来,形成更复杂的策略。例如,可以先使用折扣策略,再使用运费策略。
策略模式是一种非常有用的设计模式,可以帮助我们编写更加灵活和可维护的代码。在实际应用中,可以根据具体的需求选择合适的策略模式实现方式。
冠军资讯
程序员DD