假设你正在为一个游戏软件中的人物设计一个继承体系。每个人物都有一个血量值,且不同的人物之间血量的变化方式也不一样,基于这样的目的,你可能会想着这样设计一个基类:
class GameCharacter
{
public:
virtual int healthValue() const; //返回人物当前的血量
//...
};
具体的人物类会继承这个 GameCharacter
基类,可以在其中对血量的计算函数 healthValue()
进行重写。在基类中,并没有将 healthValue()
函数设置为 pure virtual function ,意味着在基类中会有一个缺省的实现。
这是一种再自然不过的设计方式。实际上,我们也可以考虑其他的设计方案。
Non-virtual Interface 实现模板方法
在 C++ 的设计流派中,有一个流派主张 virtual 函数应该几乎总是成为 private 函数。他们建议,将对外接口设计为 non-virtual,并且对内调用一个 private virtual 函数进行实际的动作,如下面这样:
class GameCharacter
{
public:
virtual int healthValue() const
{
//... //做一些事前动作
int result = doHealthValue();
//... //做一些事后动作
return result;
}
//...
private:
virtual int doHealthValue() const // derived class 可以重新定义
{
//... //计算人物血量的缺省算法
}
};
这种,让客户端通过 public non-virtual 成员函数间接调用 private virtual 成员函数 的方法,称为 non-virtual interface (NVI),它是23种设计模式中模板方法(Template Method) 的一种特殊的表现形式。
NVI 的一个优点就是代码中所展现的,可以在 virtual function 执行之前和之后做一些额外的事情。比如说可以在事前 locking a mutex,然后在事后释放。
利用 function pointers 实现策略模式
这一种替代方案是基于这样一种考虑:血量的计算和人物的类型并没有关系,healthValue() 函数的执行,对于不同的人物类型来说,