设计模式(C++)-行为型模式-策略模式
一、策略模式概述
策略模式:是一种行为型设计模式,它定义了一系列算法,将每一个算法封装起来,并且使他们可以相互替换。策略模式让算法的变化独立于使用算法的客户端,使得算法可以在不修改客户端代码的情况下被灵活地选择和切换。
它的核心思想是:分离"做什么"(策略)和"谁来做/在什么环境下做"(上下文)
二、策略模式UML类图
策略模式场景
假如现在有个英雄需要使用武器对付敌人,武器有两种匕首和AK,那么选择使用哪种武器其实就是一种策略,可以将策略模式分为三部分:
Strategy 策略基类(抽象武器)
ConcreteStrategy 具体策略(使用匕首或AK)
Context 具体使用策略的对象(英雄)
具体UML类图如下

三、策略模式代码实现
cpp
//strategy.h
#pragma once
/*Strategy 模式和 Template 模式要解决的问题是相同(类似)的,都是为了给业务逻辑(算法)具体实现和抽象接口之间的解耦
简而言之,Strategy 模式是对算法的封装。处理一个问题的时候可能有多种算法,这些算法的接口(输入参数,输出参数等)都是一致的,
那么可以考虑采用Strategy 模式对这些算法进行封装,在基类中定义一个函数接口就可以了。
*/
/*假如现在有个英雄需要使用武器对付敌人,武器有两种匕首和AK,那么这么选择使用哪吧武器其实就是一种策略了那么就可以将策略模式分为三部分:
Strategy 策略基类 (抽象武器)
ConcreteStrategy 具体策略 (使用匕首或AK)
Context 具体使用策略的对象(英雄)*/
#include <iostream>
using namespace std;
//抽象武器 策略基类(抽象的策略)
class WeaponStrategy {
public:
virtual void UseWeapon() = 0;
};
//具体的策略使用匕首做武器
class Knife :public WeaponStrategy {
public:
virtual void UseWeapon() {
cout << "使用匕首" << endl;
}
};
//具体的策略 使用AK47做武器
class AK47 :public WeaponStrategy {
public:
virtual void UseWeapon() {
cout << "使用AK47" << endl;
}
};
//具体使用策略的角色
class Context
{
public:
void setWeapon(WeaponStrategy* pWeapon) {
this->pWeapon = pWeapon;
}
void ThrowWeapon() {
this->pWeapon->UseWeapon();
}
private:
WeaponStrategy* pWeapon = nullptr;
};
void testStrategy();
//strategy.cc
#include "strategy.h"
void testStrategy() {
cout << "=================strategy start===============" << endl;
Context* character = new Context;
WeaponStrategy* knife = new Knife;
WeaponStrategy* ak47 = new AK47;
//用匕首当作武器
character->setWeapon(knife);
character->ThrowWeapon();
//用AK47当作武器
character->setWeapon(ak47);
character->ThrowWeapon();
delete ak47;
ak47 = nullptr;
delete knife;
knife = nullptr;
delete character;
character = nullptr;
cout << "=================strategy end===============" << endl;
}
四、优缺点总结
优点:
- 开闭原则:无需修改上下文,就能轻松引入新的武器,只需新增一个具体策略类
- 消除条件判断:赏析文中没有任何关于具体的if-else语句,代码更简洁
- 算法服用:策略对象可以在系统的不同部分共享使用
- 运行时灵活:客户端可在运行时动态地为上下文选择并切换算法
- 职责清晰:策略类只关心如何实现特定的算法,上下文类:只关心如何调度和使用策略,不关心其实现细节。
缺点:
- 类数量增加:每个具体的策略都是一个类,如果算法很简单且数量多,会知道系统类文件操作。
- 客户端必须了解策略:客户端要知道不同策略的区别,以便选择合适的策略设置。
- 通信开销:策略接口可能强迫某些策略实现他么不需要的方法。