1 NVI (Non-Virtual Interface)
看下面的类继承关系:
class GameCharactor
{
public:
virtual void CalculateScore(const GameCharactor& charactor);
};
class ACharactor : public GameCharactor
{
public:
virtual void CalculateScore(const GameCharactor& charactor);
};
class BCharactor : public GameCharactor
{
virtual void CalculateScore(const GameCharactor& charactor);
};
我们用基类来抽象游戏中的一个角色,这个角色有一个计算自身得分的函数CalculateScore(),由于继承自此基类的每一个子类很可能都有他们自己的计算得分的方法,所以我们在设计的时候首先想到,将这个计算得分的函数定义为虚函数,子类继承并重写之。但是这样就存在两个问题,其一是可扩展性不高,假设每个子类在调用得分函数之前、之后需要做一些各自的其他操作呢,所以将基类改为如下设计,用Non-Virtual的函数取代Virtual函数作为提供给用户的借口:
class GameCharactor
{
public:
void GetScore(){ CalculateScore(*this); }
private:
virtual void CalculateScore(const GameCharactor& charactor);
};
第二个问题是如果同一个子类的不同对象需要不同的计算得分的函数呢?所以在此引入第二种方案:
2、在参数中引入函数指针
typedef void (*GetScore)(cosnt GameCharactor&) ;
void DefaultSocre(const GameCharactor& charactor){..........}
class GameCharactor
{
public:
GameCharactor(GetSocre getscore = DefaultSocre):GetCharactorScore(getscore ){}
void GetScore(){ GetCharactorScore(*this);}
private:
GetSocre GetCharactorScore;
};
这里通过传入函数指针的形式,可实现更细粒度的多态,并且还有一个好处就是可以动态改变每一个对象实例的计算得分的函数,比如可以通过SetScoreFunction()借口来实现。
3、上面第二种参数也可以通过传入对象指针的方式来实现,UML图如下:
总结:
虚函数可以用来实现继承于同一基类的不通子类之间的多态,通过引入指针或对象指针的方式可以实现更细粒度的多态,即同一子类不同对象之间的多态。上述三种方式中的后两种方式是strategy设计模式的应用。