题目描述: 策略模式
动机(Motivation)
- 在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一个性能负担。
- 如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?
模式定义
定义一系列算法,把它们一个个封装起来,并且使它们可互相替换(变化)。该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展,子类化)。
——《设计模式》 GoF
要点总结
- Strategy及其子类为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换。
- Strategy模式提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需要Strategy模式。
- 如果Strategy对象没有实例变量,那么各个上下文可以共享同一个Strategy对象,从而节省对象开销。
代码结构
.
├── build.sh
├── clearBuild.sh
├── CMakeLists.txt
├── src
│ ├── examStu.cpp
│ ├── include
│ │ └── examStu.h
│ └── main.cpp
源码例子1
examStu.h
#ifndef _EXANSTU__
#define _EXANSTU__
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Strategy
{
public:
//这里有一个小知识 :
/*
在某些类里声明纯虚析构函数很方便。纯虚函数将产生抽象类——不能实例化的类(即不能创建此类型的对象)。有些时候,你想使一个类成为抽象类,
但刚好又没有任何纯虚函数。怎么办?因为抽象类是准备被用做基类的,基类必须要有一个虚析构函数,纯虚函数会产生抽象类,
所以方法很简单:在想要成为抽象类的类里声明一个纯虚析构函数。
这里是一个例子:
class awov {
public:
virtual ~awov() = 0; // 声明一个纯虚析构函数
};
这个类有一个纯虚函数,所以它是抽象的,而且它有一个虚析构函数,所以不会产生析构函数问题。但这里还有一件事:必须提供纯虚析构函数的定义:
awov::~awov() {} // 纯虚析构函数的定义
这个定义是必需的,因为虚析构函数工作的方式是:最底层的派生类的析构函数最先被调用,然后各个基类的析构函数被调用。
这就是说,即使是抽象类,编译器也要产生对~awov的调用,所以要保证为它提供函数体。如果不这么做,链接器就会检测出来,最后还是得回去把它添上。
*/
virtual ~Strategy()=0;
virtual void AlgorithmInterface() = 0;
};
class ConcreteStrategyA:public Strategy
{
public:
~ConcreteStrategyA(){
};
void AlgorithmInterface() override {
cout << "from ConcreteStrategyA." << endl;}
};
class ConcreteStrategyB:public Strategy
{
public:
~ConcreteStrategyB(){
};
void AlgorithmInterface() override {
cout << "from ConcreteStrategyB." << endl;}
};
class context
{
public:
context(){
};
context(Strategy* pStrategy):pContextStrategy(pStrategy){
}
~context(){
};
void ContextStrategy()
{
pContextStrategy->AlgorithmInterface();
}
Strategy * pContextStrategy;
private:
};
#endif
main.cpp
#include <iostream>
#include <string>
#include <memory>
#include "examStu.h"
using namespace std;
int main(int argc, char *argv[])
{
Strategy* pA = new ConcreteStrategyA();
Strategy* pB = new ConcreteStrategyB();
context *pcontextA = new context(pA);
pcontextA->pContextStrategy->AlgorithmInterface(); //这样可以调用其他类中的函数
context *pcontextB = new context(pB);
pcontextB->ContextStrategy();
delete pA;
delete pB;
delete pcontextA;
delete pcontextB;
return 0;
}
源码例子2 (结合简单模式)
代码结构
.
├── build.sh
├── clearBuild.sh
├── CMakeLists.txt
├── src
│ ├── examStu.cpp
│ ├── include
│ │ └── examStu.h
│ └── main.cpp
examStu.h
#ifndef _EXANSTU__
#define _EXANSTU__
#include <iostream>
#include <string>
#include <vector>
using namespace std;
typedef enum _StrategyType
{
CONCRETE_STRATAGY_BASE = 0,
CONCRETE_STRATAGY_A = 1,
CONCRETE_STRATAGY_B = 2,
CONCRETE_STRATAGY_ERROR = -999,
}eStrategyType;
class Strategy
{
public:
virtual ~Strategy()=0;
virtual void AlgorithmInterface() = 0;
};
class ConcreteStrategyA:public Strategy
{
public:
ConcreteStrategyA(){
}
~ConcreteStrategyA(){
cout << "~ConcreteStrategyA()" << endl;};
void AlgorithmInterface() override {
cout << "from ConcreteStrategyA." << endl;}
};
class ConcreteStrategyB:public Strategy
{
public:
ConcreteStrategyB(){
}
~ConcreteStrategyB(){
cout << "~ConcreteStrategyB()" << endl;};
void AlgorithmInterface() override {
cout << "from ConcreteStrategyB." << endl;}
};
class Context
{
public:
Context(){
};
~Context(){
cout << "~Context()" << endl;}
Context(eStrategyType strategyType);
void ContextStrategy();
private:
std::shared_ptr<Strategy> pStrategy;
};
#endif
main.cpp
#include <iostream>
#include <string>
#include <memory>
#include "examStu.h"
using namespace std;
int main(int argc, char *argv[])
{
Context *pcontextA = new Context(CONCRETE_STRATAGY_A);
pcontextA->ContextStrategy();
Context *pcontextB = new Context(CONCRETE_STRATAGY_B);
pcontextB->ContextStrategy();
delete pcontextA;
delete pcontextB;
return 0;
}