一、什么是策略模式?
策略模式(Strategy Pattern) 的核心思想非常简单:
把一组可以互相替换的算法/行为封装起来,让程序在运行时可以自由切换。
也就是说:
原来的代码:
if (条件A)
算法A
else if (条件B)
算法B
else if (条件C)
算法C
策略模式改成:
Context
|
v
Strategy接口
/ | \\
/ | \\
策略A 策略B 策略C
Context 不关心具体怎么做,只需要调用:
strategy->execute();
二、最简单的 C++ 例子
比如我们做一个计算器,有三种计算方式:
加法
减法
乘法
class Strategy
{
public:
virtual ~Strategy() = default;
virtual int calculate(int a, int b) = 0;
};
这里的 Strategy 就是策略基类。
它规定:
所有策略都必须实现 calculate()。
class AddStrategy : public Strategy
{
public:
int calculate(int a, int b) override
{
return a + b;
}
};
class SubStrategy : public Strategy
{
public:
int calculate(int a, int b) override
{
return a – b;
}
};
class MulStrategy : public Strategy
{
public:
int calculate(int a, int b) override
{
return a * b;
}
};
三、Context:使用策略
我们再定义一个 Calculator:
class Calculator
{
public:
void setStrategy(std::unique_ptr<Strategy> strategy)
{
m_strategy = std::move(strategy);
}
int calculate(int a, int b)
{
if (!m_strategy)
return 0;
return m_strategy->calculate(a, b);
}
private:
std::unique_ptr<Strategy> m_strategy;
};
这里的 Calculator 就是 Context(上下文)。
它不关心:
a + b
还是:
a – b
还是:
a * b
它只知道:
m_strategy->calculate(a, b);
四、使用
#include <iostream>
#include <memory>
int main()
{
Calculator calculator;
// 使用加法策略
calculator.setStrategy(
std::make_unique<AddStrategy>()
);
std::cout << calculator.calculate(10, 5) << std::endl;
// 15
// 切换成减法策略
calculator.setStrategy(
std::make_unique<SubStrategy>()
);
std::cout << calculator.calculate(10, 5) << std::endl;
// 5
// 切换成乘法策略
calculator.setStrategy(
std::make_unique<MulStrategy>()
);
std::cout << calculator.calculate(10, 5) << std::endl;
// 50
return 0;
}
这里最重要的地方就是:
calculator.setStrategy(
std::make_unique()
);
然后:
calculator.setStrategy(
std::make_unique()
);
运行过程中直接更换算法。
这就是策略模式最核心的地方。
五、如果不用策略模式会怎样?
例如你写:
class Calculator
{
public:
int calculate(int a, int b, char op)
{
if (op == '+')
{
return a + b;
}
else if (op == '-')
{
return a – b;
}
else if (op == '*')
{
return a * b;
}
else if (op == '/')
{
return a / b;
}
return 0;
}
};
刚开始没问题。
但是以后增加:
%
幂运算
平方根
平均值
最大值
最小值
…
就会变成:
if (...)
{
}
else if (...)
{
}
else if (...)
{
}
else if (...)
{
}
else if (...)
{
}
else if (...)
{
}
Calculator 会越来越复杂。
六、策略模式解决了什么?
采用策略模式:
class Strategy
{
public:
virtual ~Strategy() = default;
virtual int calculate(int a, int b) = 0;
};
然后:
Strategy
|
┌──────────┼──────────┐
↓ ↓ ↓
AddStrategy SubStrategy MulStrategy
以后增加除法:
class DivStrategy : public Strategy
{
public:
int calculate(int a, int b) override
{
return a / b;
}
};
Calculator 完全不需要修改。
这就是策略模式非常重要的一个优点:
增加策略时,不需要修改 Context。
七、结合 Qt/C++ 项目理解
做工业软件、设备通信、图像处理时,策略模式其实非常常见。
例如你有不同的图像处理算法:
图像处理
|
├── 二值化
├── 灰度化
├── 归一化
├── 伪彩色
└── 滤波
可以设计成:
class ImageProcessStrategy
{
public:
virtual ~ImageProcessStrategy() = default;
virtual cv::Mat process(const cv::Mat& src) = 0;
};
二值化策略
class ThresholdStrategy : public ImageProcessStrategy
{
public:
cv::Mat process(const cv::Mat& src) override
{
cv::Mat dst;
cv::threshold(
src,
dst,
128,
255,
cv::THRESH_BINARY
);
return dst;
}
};
归一化策略
class NormalizeStrategy : public ImageProcessStrategy
{
public:
cv::Mat process(const cv::Mat& src) override
{
cv::Mat dst;
cv::normalize(
src,
dst,
0,
255,
cv::NORM_MINMAX
);
return dst;
}
};
ImageProcessor
class ImageProcessor
{
public:
void setStrategy(
std::unique_ptr<ImageProcessStrategy> strategy)
{
m_strategy = std::move(strategy);
}
cv::Mat process(const cv::Mat& src)
{
if (!m_strategy)
return cv::Mat();
return m_strategy->process(src);
}
private:
std::unique_ptr<ImageProcessStrategy> m_strategy;
};
使用:
ImageProcessor processor;
// 使用二值化
processor.setStrategy(
std::make_unique<ThresholdStrategy>()
);
cv::Mat dst = processor.process(src);
// 然后需要归一化:
processor.setStrategy(
std::make_unique<NormalizeStrategy>()
);
dst = processor.process(src);
八、Qt 项目里更典型的例子
比如你有不同的通信方式:
设备通信
|
├── TCP
├── UDP
├── Serial
└── Modbus
可以定义:
class CommunicationStrategy
{
public:
virtual ~CommunicationStrategy() = default;
virtual bool connectDevice() = 0;
virtual bool sendData(
const QByteArray& data) = 0;
virtual QByteArray receiveData() = 0;
};
TCP:
class TcpStrategy : public CommunicationStrategy
{
public:
bool connectDevice() override
{
qDebug() << "TCP connect";
return true;
}
bool sendData(const QByteArray& data) override
{
qDebug() << "TCP send:" << data;
return true;
}
QByteArray receiveData() override
{
qDebug() << "TCP receive";
return {};
}
};
串口:
class SerialStrategy : public CommunicationStrategy
{
public:
bool connectDevice() override
{
qDebug() << "Serial connect";
return true;
}
bool sendData(const QByteArray& data) override
{
qDebug() << "Serial send:" << data;
return true;
}
QByteArray receiveData() override
{
qDebug() << "Serial receive";
return {};
}
};
然后:
class Device
{
public:
void setStrategy(
std::unique_ptr<CommunicationStrategy> strategy)
{
m_strategy = std::move(strategy);
}
bool connectDevice()
{
return m_strategy &&
m_strategy->connectDevice();
}
bool sendData(const QByteArray& data)
{
return m_strategy &&
m_strategy->sendData(data);
}
private:
std::unique_ptr<CommunicationStrategy> m_strategy;
};
使用:
Device device;
// TCP
device.setStrategy(
std::make_unique<TcpStrategy>()
);
device.connectDevice();
device.sendData("Hello");
// 如果改成串口:
device.setStrategy(
std::make_unique<SerialStrategy>()
);
Device 的代码完全不用修改。
九、策略模式的结构
你可以记住这三个角色:
┌──────────────────────┐
│ Context │
│ │
│ 保存 Strategy │
│ 调用 Strategy │
└──────────┬───────────┘
│
↓
┌──────────────────────┐
│ Strategy │
│ 策略接口 │
│ │
│ execute() │
└──────────┬───────────┘
│
┌────┼────┐
↓ ↓ ↓
StrategyA B C
对应到 C++:
class Strategy
{
public:
virtual void execute() = 0;
};
class StrategyA : public Strategy
{
public:
void execute() override
{
// 算法A
}
};
class StrategyB : public Strategy
{
public:
void execute() override
{
// 算法B
}
};
class Context
{
private:
std::unique_ptr<Strategy> strategy;
};
十、策略模式和简单工厂的区别
这个很容易混淆。
工厂模式
解决的是:
“我要创建哪个对象?”
例如:
auto strategy = StrategyFactory::create(“tcp”);
策略模式
解决的是:
“我要使用哪个算法/行为?”
例如:
device.setStrategy(
std::make_unique()
);
两者实际上可以结合:
Factory
│
↓
创建具体 Strategy
│
↓
Context
│
↓
执行具体策略
在 Qt + C++ + 工业设备通信/图像处理项目里,这种组合非常实用。
一句话记忆:
策略模式 = 把容易变化的算法抽出来,让它们可以互相替换。
如果你正在系统学习 GoF 设计模式,那么策略模式可以重点理解成:“把一堆 if/else 中变化的行为,变成一个个独立的类。”
网硕互联帮助中心



评论前必须登录!
注册