过去,我看到策略模式被解释为一种机制,允许函数/类的用户为该函数/类提供自己的功能。
我一直被教导实现该模式的方法是将函数指针放入类/函数中并在内部调用它们,从而允许程序员提供自己的“策略”,这些策略将由这些函数和对象在内部使用。
最近环顾四周,我发现策略模式似乎总是通过使用继承层次结构来解释/定义,如下所示:
这是意见/实现的差异,还是函数指针传递实际上并不是策略模式的变体?我最感兴趣,所以当我评论或解释我的代码时我不会让人们感到困惑:)
您只需在没有函数指针的语言中使用继承(例如:Java)。
就个人而言,我更喜欢
std::function
而不是原始函数指针,因为它接受更广泛的参数,并允许您维护策略对象中的状态。
此外,如果您已经知道编译时的策略,您甚至可以使用模板,从而节省函数指针和
std::function
对象的空间和运行时开销。
在我看来,使用函数指针实现策略模式是在不支持 OOP 的语言(例如 C)中完成的。
在支持 OOP 的语言中,最好使用类来实现:继承、虚函数(即运行时多态性)、接口等。通常,这是运行时策略模式,这意味着,您只需在运行时切换到其他策略模式即可更改程序的行为。
在C++中,还有一种编译时策略模式,俗称基于策略的设计。
无论如何,类可以维护状态,而函数指针则不能。这是使用类的最大优势。
使用函数指针来实现策略是基于继承的版本的退化情况。如您所知,该模式的基本核心是能够在运行时提供或修改某个进程的组件。该组件可以是一个函数,也可以是一个对象。如果策略由多个位组成,那么基于继承的版本确实更好,因为一个对象可以将多个方法打包在一起;如果只有一块,那么函数指针也差不多。
IMO,策略模式可以使用以下方式实现:
std::function
,并使用 lambda。接口对象可以有状态,因此可以维护成员变量。函数指针不能。
这是C++策略模式的实用代码。我希望纯虚函数的使用(而不是 Java 中的接口)是不言自明的。
#include <iostream>
#include <fstream>
#include <string.h>
using namespace std;
class Strategy;
class TestBed{
public:
TestBed(){
myStrategy = NULL;
}
void setBehavior(int type);
Strategy *myStrategy;
};
class Strategy{
public:
void performBehavior(){
behave();
}
private:
virtual void behave() = 0;
};
class behaviorOne: public Strategy{
private:
void behave(){
cout << "left strategy" << endl;
}
};
class behaviorTwo: public Strategy{
private:
void behave(){
cout << "right strategy" << endl;
}
};
class behaviorThree: public Strategy{
private:
void behave(){
cout << "center strategy" << endl;
}
};
void TestBed::setBehavior(int type){
delete myStrategy;
if (type == 0)
myStrategy = new behaviorOne();
else if (type == 1)
myStrategy = new behaviorTwo();
else if (type == 2)
myStrategy = new behaviorThree();
}
int main(){
TestBed test;
int answer;
while(1){
cout << "Exit(other) Left(0) Right(1) Center(2): ";
cin >> answer;
if(answer > 2) break;
test.setBehavior(answer);
test.myStrategy->performBehavior();
}
return 0;
}