Non-Virtual Interface (NVI) 手法实现
这个方法主张 virtual
函数应该几乎总是 private
。这个流派认为,较好的设计是保留 healthValue
为 public
成员函数,但让它成为 non-virtual
,并调用一个 private virtual
函数进行实际工作
class GameCharacter{
public:
int healthValue() const{ // derived classes 不重新定义它
... // 一些事前工作
int retVal = doHealthValue(); // 真正的工作
... // 时候工作
return retVal;
}
...
private:
virtual int doHealthValue() const{ // derived classes 可重新定义它
... // 缺省算法,计算相关值
}
};
Function Pointer 实现 Strtegy 模式
class GameCharacter; // 前置声明
// 以下函数时计算健康指数的缺省算法
int defaultHealthCalc(const GameCharacter& gc);
class GameCharacter{
public:
typedef int (*HealthCalcFunc)(const GameCharacter&); // typedef了一个函数指针类型
explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc) : healthFunc(hcf){}
int healthValue() const
{ return healthFunc(*this); }
...
private:
HealthCalcFunc healthFunc;
};
这种方式相对更常见
- 同一任务类型之不同实体可以有不同的健康计算函数
class EvilBadGuy:public GameCharacter{
public:
explicit EvilBadGuy(HealthCalcFunc hcf = defaultHealthCalc)
: GameCharacter(hcf)
{...}
};
int loseHealthQuickly(const GameCharacter&); // 健康指数计算函数1
int loseHealthSlowly(const GameCharacter&); // 健康指数计算函数2
EvilBadGuy ebg1(loseHealthQuickly); // 相同类型的人物搭配
EvilBadGuy ebg2(loseHealthSlowly); // 不同的健康计算方式
藉由 tr1::function 完成 Strategy 模式
通过 tr1:function
接触了之前要求必须是个函数,而不能是某种 “象函数的东西” (例如函数对象) 的限制
tr1::function:
class GameCharacter;
int defaultHealthCalc(const GameCharacter& gc);
class GameCharacter{
public:
// HealthCalcFunc 可以是任何 "可调用物" (callable entity), 可被调用并接受
// 任何兼容于 GameCharacter 之物,返回任何兼容于 int 的东西
typedef std::tr1::function<int (const GameCharacter&)> HealthCalcFunc;
explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc)
: healthFunc(hcf)
{}
int healthValue() const
{ return healthFunc(*this); }
private:
HealthCalcFunc healthFunc;
};
实例:
short calcHealth(const GameCharacter&); // 健康计算函数
// 其返回类型是 non-int
struct HealthCalculator{ // 为计算健康而设计的函数对象
int operator()(const GameCharacter&) const
{ ... }
};
class GameLevel{
public:
float health(const GameCharacter&) const; // 成员函数,用以计算健康
... // 注意其 not-int 返回类型
};
class EvilBadGuy:pulic GameCharacter{ // 同前
...
};
class EyeCandyCharacter:public GameCharacter{ // 另一个任务类型
... // 假设其构造函数与
}; // EvilBadGuy 同
EvilBadGuy ebg1(calcHealth); // 人物1,使用某个
// 函数计算
EyeCandyCharacter ecc1(HealthCalculator()); // 人物2,使用某个
// 函数对象计算
// Effective C++ P175
GameLevel currentLevel;
...
EvilBadGuy ebg2( // 人物3,使用某个
std::str1::bind(&GameLevel::health, // 成员函数计算
currentLevel,
_1)
);
古典 Strategy 模式
class GameCharacter; // 前置声明
class HealthCalcFunc{
public:
...
virtual int calc(const GameCharacter& gc) const
{ ... }
...
};
Health CalcFunc defaultHealthCalc;
class GameCharacter{
public:
explicit GameCharacter(HealthCalcFunc* phcf = &defaultHealthCalc)
: pHealthCalc(phcf)
{}
int healthValue() const
{ return pHealthCalc->calc(*this); }
...
private:
HealthCalcFunc* pHealthClac;
};