策略模式学习

0.引言

最近想整理一下代码。我的想法是使用继承的方案,使用多态写一个interface,然后不同的方法来继承它。最近ChatGPT比较火,顺便问了一下它:

在C++代码设计中,我对同一算法设计了不同的实现,例如计算平均值,我实现了method_a、method_b、method_c三种计算方式,请问我该使用那种设计模式将其组织起来,请给出一个优美的代码设计示例。

它推荐的是策略模式,我也觉得很适合我的使用场景,因此在此处记录一下它的回答,并未整理,以作后续参考。

在这里插入图片描述

1.策略模式

这个问题的答案取决于您的具体要求。但是,如果您想要能够随时更改计算平均值的方法,那么您可以使用策略模式来设计您的代码。

策略模式允许将算法封装到独立的类中,并通过组合来使用它们。这使您可以在运行时更改算法,而无需修改原始代码。例如,您可以在您的代码中定义一个名为 AverageCalculator 的类,该类具有一个成员函数 double calculate(std::vector<double> values),用于计算给定数值的平均值。您还可以定义三个策略类,分别为 MethodAMethodBMethodC,每个类都实现了 calculate 函数,用于计算平均值。然后,您可以在 AverageCalculator 类中将其中一个策略类作为数据成员,并使用它来实现 calculate 函数。

下面是一个使用策略模式实现的示例代码:

Copy code
#include <iostream>
#include <vector>

// 定义三个策略类,用于计算平均值
class MethodA {
public:
  double calculate(const std::vector<double>& values) {
    // 此处是具体的计算方法
  }
};

class MethodB {
public:
  double calculate(const std::vector<double>& values) {
    // 此处是具体的计算方法
  }
};

class MethodC {
public:
  double calculate(const std::vector<double>& values) {
    // 此处是具体的计算方法
  }
};
class AverageCalculator {
public:
  // 构造函数,用于接收一个策略类对象
  AverageCalculator(std::unique_ptr<Method> m) : method_(std::move(m)) {}

  // 计算平均值
  double calculate(const std::vector<double>& values) {
    return method_->calculate(values);
  }

private:
  std::unique_ptr<Method> method_; // 保存策略类对象
};
int main() {
  std::vector<double> values = {1.0, 2.0, 3.0};

  // 使用策略类 MethodA 计算平均值
  AverageCalculator calc1(std::make_unique<MethodA>());
  std::cout << calc1.calculate(values) << std::endl;

  // 使用策略类 MethodB 计算平均值
  AverageCalculator calc2(std::make_unique<MethodB>());
  std::cout << calc2.calculate(values) << std::endl;

  // 使用策略类 MethodC 计算平均值
  AverageCalculator calc3(std::make_unique<MethodC>());
  std::cout << calc3.calculate(values) << std::endl;

  return 0;
}

在上面的代码中,我们定义了三个策略类,用于实现不同的计算平均值的方法。接着,我们定义了一个 AverageCalculator 类,该类包含一个接收一个策略类对象的构造函数和一个计算平均值的函数。在 main 函数中,我们创建了三个 AverageCalculator 对象,分别使用三个策略类来计算平均值。

使用策略模式的好处在于,如果您想要更改算法的实现方式,只需更改策略类的代码,而不需要修改 AverageCalculator 类的代码。此外,策略模式还允许您增加新的策略类来实现新的算法,而无需修改原有代码。

不过,需要注意的是,使用策略模式需要您定义多个策略类,并且每个策略类都需要实现相同的接口,这会增加代码的复杂度。因此,是否使用策略模式取决于您的具体需求。

最后,需要注意的是,上面的代码仅供参考,并不能保证能够在您的环境中正常编译和运行。

点评:ChatGPT给出的这个示例差一个Method基类,下面给出一个经典的例子

2.一个经典示例代码

策略模式是一种常用的设计模式,它允许将算法封装到独立的类中,并通过组合来使用它们。这使您可以在运行时更改算法,而无需修改原始代码。例如,您可以使用策略模式来实现一个简单的计算器程序,其中包含多种运算符,如加、减、乘、除。

下面是一个使用 C++ 实现策略模式的经典示例代码:

#include <iostream>
#include <memory>

// 定义运算符接口
class Operator {
public:
  virtual double calculate(double a, double b) = 0;
};

// 定义具体的运算符类
class AddOperator : public Operator {
public:
  double calculate(double a, double b) override {
    return a + b;
  }
};

class SubOperator : public Operator {
public:
  double calculate(double a, double b) override {
    return a - b;
  }
};

class MulOperator : public Operator {
public:
  double calculate(double a, double b) override {
    return a * b;
  }
};

class DivOperator : public Operator {
public:
  double calculate(double a, double b) override {
    return a / b;
  }
};

// 定义计算器类
class Calculator {
public:
  Calculator(std::unique_ptr<Operator> op) : op_(std::move(op)) {}

  double calculate(double a, double b) {
    return op_->calculate(a, b);
  }

private:
  std::unique_ptr<Operator> op_;
};

int main() {
  Calculator calc1(std::make_unique<AddOperator>());
  std::cout << calc1.calculate(1.0, 2.0) << std::endl;

  Calculator calc2(std::make_unique<SubOperator>());
  std::cout << calc2.calculate(1.0, 2.0) << std::endl;

  Calculator calc3(std::make_unique<MulOperator>());
  std::cout << calc3.calculate(1.0, 2.0) << std::endl;

  Calculator calc4(std::make_unique<DivOperator>());
  std::cout << calc4.calculate(1.0, 2.0) << std::endl;

  return 0;
}

在这里插入图片描述

对照UML类图看就很清晰了。


实践的时候发现,策略模式需要将所有的算法暴露给客户端。比如在上面的代码中,main函数文件必须包含加减乘除四个头文件才能创建对象。 还是工厂模式更适合。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值