用最简单的方式上手设计模式--策略模式(一直更新!!)
面试的时候,设计模式好像问的挺多,但是cpper大部分都不会去买书或者看视频,而且有些视频讲的不明不白的,于是我决定了!!!开一个专栏专门唠设计模式,不定期更新。
我觉得上手最快的方式,就是先了解一个大概的设计理念,然后熟悉设计模式的模板,对,设计模式是实践出来的,所以有模板,一定要背下来,然后再了解一下运用场景,解决了什么问题,把它运用起来,就OK啦!
这个系列将不定期更新,接下来先讲解策略模式:
什么是策略模式
策略模式是一种行为设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以互相替换。通过使用策略模式,可以在运行时选择算法的行为。
下面是一个使用C++实现的策略模式的示例:
#include <iostream>
// 定义策略接口
class Strategy {
public:
virtual void algorithm() = 0;
};
// 策略的具体实现A
class ConcreteStrategyA : public Strategy {
public:
void algorithm() override {
std::cout << "Using ConcreteStrategyA" << std::endl;
}
};
// 策略的具体实现B
class ConcreteStrategyB : public Strategy {
public:
void algorithm() override {
std::cout << "Using ConcreteStrategyB" << std::endl;
}
};
// 定义策略上下文,负责维护策略对象并提供调用接口
class Context {
public:
Context(Strategy* strategy) : strategy_(strategy) {}
void set_strategy(Strategy* strategy) {
strategy_ = strategy;
}
void execute_algorithm() {
strategy_->algorithm();
}
private:
Strategy* strategy_;
};
int main() {
// 创建策略上下文,使用策略A
ConcreteStrategyA strategy_a;
Context context(&strategy_a);
// 调用策略A的算法
context.execute_algorithm();
// 切换策略为B
ConcreteStrategyB strategy_b;
context.set_strategy(&strategy_b);
// 调用策略B的算法
context.execute_algorithm();
return 0;
}
上面Strategy
是策略接口,ConcreteStrategyA
和 ConcreteStrategyB
是具体的策略实现,Context
是策略上下文,负责维护策略对象并提供调用接口。客户端可以通过调用 Context
的 execute_algorithm
方法来执行具体的策略算法。
在运行时,客户端可以通过修改策略上下文中的策略对象,来选择使用不同的策略算法。
在上面的代码中,策略对象通过指针传递,而不是值传递,这可以减少对象复制的开销。同时,策略对象的生命周期也需要客户端自行管理。
应用场景
策略模式适用于以下场景:
-
多算法替换:当一个系统需要根据不同的情况选择不同的算法或策略时,可以使用策略模式。例如,对于排序算法,可以根据数据量大小选择使用快速排序、归并排序或插入排序等不同的排序策略。
-
避免条件语句:当代码中存在大量的条件语句,根据不同条件执行不同的操作时,可以考虑使用策略模式来消除这些条件语句。通过将每个条件分支封装成一个独立的策略类,可以简化代码逻辑并提高代码的可维护性和可扩展性。
-
算法的扩展和维护:当系统中的算法经常变化或需要新增算法时,使用策略模式可以方便地扩展和维护代码。只需要添加新的策略类,并将其注册到策略上下文中,而无需修改现有的代码。
-
隔离变化:策略模式可以将不同的行为封装到不同的策略类中,从而将变化的部分和稳定的部分分离开来。这样,在需求变更时,只需要修改相应的策略类或添加新的策略类,而不会对其他部分造成影响。
-
可扩展的插件系统:通过策略模式,可以实现一个可扩展的插件系统。每个插件对应一个策略类,系统可以根据需要动态加载和使用不同的插件。
总结一下,策略模式适用于需要在运行时选择不同算法或策略的场景,以及需要将算法的实现与调用代码解耦的情况。它能够提高代码的灵活性、可维护性和可扩展性。常见的应用包括排序算法、支付方式选择、日志记录级别等。
一个详细具体的场景
假设我们正在开发一个电商平台,其中有一个商品促销活动模块。在该模块中,不同的促销活动可以根据不同的策略来计算商品的折扣价格。这里可以使用策略模式来实现。
具体示例代码如下:
#include <iostream>
#include <string>
// 抽象策略类
class DiscountStrategy {
public:
virtual double applyDiscount(double price) const = 0;
};
// 具体策略类1:固定折扣
class FixedDiscountStrategy : public DiscountStrategy {
public:
double applyDiscount(double price) const override {
return price * 0.8; // 固定折扣为80%
}
};
// 具体策略类2:满减
class ThresholdDiscountStrategy : public DiscountStrategy {
public:
double applyDiscount(double price) const override {
if (price >= 100) {
return price - 20; // 满100减20
} else {
return price;
}
}
};
// 上下文类
class PromotionContext {
private:
DiscountStrategy* strategy;
public:
PromotionContext(DiscountStrategy* strategy) : strategy(strategy) {}
double calculateDiscountedPrice(double price) const {
return strategy->applyDiscount(price);
}
};
int main() {
// 创建具体策略对象
DiscountStrategy* strategy1 = new FixedDiscountStrategy();
DiscountStrategy* strategy2 = new ThresholdDiscountStrategy();
// 创建上下文对象,并指定具体策略
PromotionContext context1(strategy1);
PromotionContext context2(strategy2);
double price = 120; // 商品原价
// 计算折扣后的价格
double discountedPrice1 = context1.calculateDiscountedPrice(price);
double discountedPrice2 = context2.calculateDiscountedPrice(price);
std::cout << "原价: " << price << std::endl;
std::cout << "固定折扣后的价格: " << discountedPrice1 << std::endl;
std::cout << "满减后的价格: " << discountedPrice2 << std::endl;
// 释放资源
delete strategy1;
delete strategy2;
return 0;
}
在上述示例中,我们定义了抽象策略类 DiscountStrategy
,它声明了一个纯虚函数 applyDiscount()
用于计算折扣价格。然后,我们实现了两个具体策略类 FixedDiscountStrategy
和 ThresholdDiscountStrategy
,它们分别根据不同的折扣策略来计算商品的折扣价格。
我们还定义了上下文类 PromotionContext
,它包含一个指向抽象策略类的指针,并通过构造函数接收具体策略对象。上下文类提供了一个方法 calculateDiscountedPrice()
,用于调用具体策略对象的 applyDiscount()
方法计算折扣后的价格。
在主函数中,我们创建了具体策略对象,并将其传递给上下文对象,然后
调用上下文对象的方法来计算折扣后的价格。这样,我们可以根据不同的策略计算商品的折扣价格,而不需要修改客户端代码。
这个例子中的电商平台可以根据需要定义更多的促销策略,例如打折、满减、满赠等,通过策略模式可以很方便地扩展和切换不同的促销策略,而不需要修改已有的代码逻辑。
代码示例
以下是十个策略模式的C++代码示例:
- 策略模式的基本结构
class Strategy {
public:
virtual void execute() = 0;
};
class ConcreteStrategyA : public Strategy {
public:
void execute() override {
// 实现具体策略A的代码
}
};
class ConcreteStrategyB : public Strategy {
public:
void execute() override {
// 实现具体策略B的代码
}
};
class Context {
private:
Strategy* strategy_;
public:
Context(Strategy* strategy) : strategy_(strategy) {}
void executeStrategy() {
strategy_->execute();
}
};
- 策略模式的使用示例
int main() {
Strategy* strategyA = new ConcreteStrategyA();
Strategy* strategyB = new ConcreteStrategyB();
Context contextA(strategyA);
Context contextB(strategyB);
contextA.executeStrategy();
contextB.executeStrategy();
delete strategyA;
delete strategyB;
return 0;
}
- 策略模式的简化版
class Context {
private:
function<void()> strategy_;
public:
Context(function<void()> strategy) : strategy_(strategy) {}
void executeStrategy() {
strategy_();
}
};
int main() {
Context contextA([]() {
// 实现具体策略A的代码
});
Context contextB([]() {
// 实现具体策略B的代码
});
contextA.executeStrategy();
contextB.executeStrategy();
return 0;
}
- 策略模式的模板版
template<typename T>
class Strategy {
public:
virtual void execute(T& data) = 0;
};
template<typename T>
class ConcreteStrategyA : public Strategy<T> {
public:
void execute(T& data) override {
// 实现具体策略A的代码
}
};
template<typename T>
class ConcreteStrategyB : public Strategy<T> {
public:
void execute(T& data) override {
// 实现具体策略B的代码
}
};
template<typename T>
class Context {
private:
Strategy<T>* strategy_;
public:
Context(Strategy<T>* strategy) : strategy_(strategy) {}
void executeStrategy(T& data) {
strategy_->execute(data);
}
};
int main() {
Context<int> contextA(new ConcreteStrategyA<int>());
Context<int> contextB(new ConcreteStrategyB<int>());
int data = 10;
contextA.executeStrategy(data);
contextB.executeStrategy(data);
return 0;
}
- 策略模式的模板版简化版
template<typename T>
class Context {
private:
function<void(T&)> strategy_;
public:
Context(function<void(T&)> strategy) : strategy_(strategy) {}
void executeStrategy(T& data) {
strategy_(data);
}
};
int main() {
Context<int> contextA([](int& data) {
// 实现具体策略A的代码
});
Context<int> contextB([](int& data) {
// 实现具体策略B的代码
});
int data = 10;
contextA.executeStrategy(data);
contextB.executeStrategy(data);
return 0;
}
- 策略模式的多态版
class Strategy {
public:
virtual void execute() = 0;
};
class ConcreteStrategyA : public Strategy {
public:
void execute() override {
// 实现具体策略A的代码
}
};
class ConcreteStrategyB : public Strategy {
public:
void execute() override {
// 实现具体策略B的代码
}
};
class Context {
private:
Strategy* strategy_;
public:
Context(Strategy* strategy) : strategy_(strategy) {}
void executeStrategy() {
strategy_->execute();
}
};
int main() {
vector<Strategy*> strategies = {new ConcreteStrategyA(), new ConcreteStrategyB()};
for (auto strategy : strategies) {
Context context(strategy);
context.executeStrategy();
}
for (auto strategy : strategies) {
delete strategy;
}
return 0;
}
- 策略模式的多态版简化版
class Context {
private:
function<void()> strategy_;
public:
Context(function<void()> strategy) : strategy_(strategy) {}
void executeStrategy() {
strategy_();
}
};
int main() {
vector<function<void()>> strategies = {
[]() {
// 实现具体策略A的代码
},
[]() {
// 实现具体策略B的代码
}
};
for (auto strategy : strategies) {
Context context(strategy);
context.executeStrategy();
}
return 0;
}
- 策略模式的函数指针版
typedef void (*Strategy)(void);
void concreteStrategyA() {
// 实现具体策略A的代码
}
void concreteStrategyB() {
// 实现具体策略B的代码
}
class Context {
private:
Strategy strategy_;
public:
Context(Strategy strategy) : strategy_(strategy) {}
void executeStrategy() {
strategy_();
}
};
int main() {
Context contextA(concreteStrategyA);
Context contextB(concreteStrategyB);
contextA.executeStrategy();
contextB.executeStrategy();
return 0;
}
- 策略模式的函数对象版
class ConcreteStrategyA {
public:
void operator()() {
// 实现具体策略A的代码
}
};
class ConcreteStrategyB {
public:
void operator()() {
// 实现具体策略B的代码
}
};
class Context {
private:
function<void()> strategy_;
public:
Context(function<void()> strategy) : strategy_(strategy) {}
void executeStrategy() {
strategy_();
}
};
int main() {
Context contextA(ConcreteStrategyA());
Context contextB(ConcreteStrategyB());
contextA.executeStrategy();
contextB.executeStrategy();
return 0;
}
- 策略模式的Lambda表达式版
class Context {
private:
function<void()> strategy_;
public:
Context(function<void()> strategy) : strategy_(strategy) {}
void executeStrategy() {
strategy_();
}
};
int main() {
Context contextA([]() {
// 实现具体策略A的代码
});
Context contextB([]() {
// 实现具体策略B的代码
});
contextA.executeStrategy();
contextB.executeStrategy();
return 0;
}
以上是策略模式不同的实现,但是结构又是相同的,设计模式是结构化的东西,应该知道在什么时候适合用什么设计模式,能够做到融会贯通,将这种设计模式应用起来,明白应用场景,才能说是学明白了!
分享到此结束,喜欢的同学点赞收藏,祝大家秋招斩获满意的offer知乎连接!
#设计模式#