条款35:考虑virtual函数以外的其他选择

假如你正在写一个视频游戏软件,你想计算不同人物的健康指数,那么平常的方法肯定是这样实现:

class GameCharacter

{

   public:

    virtual int healthValue() const;

   ........

};

healthValue被声明为virtual,说明会提供缺省方法。但是从某个角度来讲这里存在弱点。这里考虑一些其他替代方法:

由Non-Virtual Interface手法实现Template Method模式

  较好的方法是保留healthValue为public成员函数,但让他为non-virtual,并调用一个private virtual函数:

class GameCharacter

{

   public:

   int healthValue() const

   {

     ...

     int retVal =  doHealthValue();

     ....

     return retVal;

   }

    .....

   private:

   virtual int doHealthValue() const

   {

      ....

   }

};

这样做可以在调用virtual之前做一些事前工作,如锁定互斥器,运转日志记录。在virtual结束后做一些事后工作,如解锁等。以上的手法我们可以叫做NVI手法。

NVI手法在派生类中重新定义private virtual函数,表示某些事如何被完成,在基类中表明何时被调用。
由Function Pointers实现Strategy模式

另外一个更戏剧性的设计主张“人物的健康指数的计算与人物类型无关”

class GameCharacter;

int defaultHealthCacl(const GameCharacter& gc);

class GameCharacter

{

  public:

  typedef int (*HealthFunc)(const GameCharacter&);

  explicit GameCharacter(HealthFunc hf = defaultHealthCacl):healthFunc(hf){.....}

 int healthValue() const

  { return healthFunc(*this);}

 ....

private:

  HealthFunc healthFunc;

};

同一人物类型的不同实体可以有不同的健康计算函数

class EvilBadGuy:public GameCharacter

{

  public:

   explicit EvilBadGuy(HealthFunc hf = defaultHealthCacl):GameCharacter(hf){ ... };

   ....

};

int  loseHealtQ(const GameCharacter&);

int  loseHealtS(const GameCharacter&);

EvilBadGuy ebg1(loseHealthQ);

EvilBadGuy ebg2(loseHealthS);

某些人物健康指数计算函数可以在运行期间变更,替代当前的健康指数。

这里的健康指数计算函数不再是类的成员函数的一部分,不再属于继承体系。

如果根据该人物的public接口计算是没有什么问题的,但是要是non-public呢。实际上当我们将class内的某个机能替换到class外部去做都是存在争议的。一般来说唯一解决的方法是弱化class的封装性。如friend函数。

由tr1::function完成strategy模式

    在上面我们要求健康计算函数是一个函数,现在我们觉得这种做法过于死板。为什么不是像函数的东西呢,返回值为什么不可以是可以转换为int的类型呢?我们不再使用函数指针,而是用函数对象tr1::function。

tr1::function:

class GameCharacter;

int defaultHealth(const GameCharacter& gc);

class GameCharacter

{

   public:

   typedef std::tr1::function<int (const GameCharater&)> HealthFunc;

  explicit GameCharacter(HealthFunc hf = defaultHealth):healthFunc(hf){   .......  }

  int healthValue() const

  { return healthFunc(*this);  }

  ....

  private:

  HealtFunc healthFunc;

};

上面只是使用了函数对象,其他地方和以前的设计是一样的,但是他的功能是如此的强大:

short call(const GameCharacter&);

struct HealtCall

{

  int operator()(const GameCharacter&) const{.......}

};

class GameLevel

{

   public:

    float health(const GameCharacter&) const;

   ........

};

class Evil:public GameCharacter

{

   ....

};

class Eye:public GameCharacter

{.........};

Evi eg1(call);

Eye eye(HealthCall());

GameLevel cur;

...

Evil eg2(std::tr1::bind(&GameLevel::health,cur,_1));

我们可以看到它是如此的强大。

古典的Strategy模式

健康计算函数做成一个分离的继承体系中的virtual成员函数。

class GameCharacter;
class HealthCalcFunc {
    ...
    virtual int calc(const GameCharacter& gc) const
    {...}
    ...
};
HealthCalcFunc defaultHealthCalc;
class GameCharacter {
public:
    explicit GameCharacter(HealthCalcFunc* phcf = &defaultHealthCalc)
        :pHealthCalc(phcf);
    {}
    int healthValue() const
    {
        return pHealthCalc->calc(*this);
    }
    ...
private:
    HealthCalcFunc* pHealthCalc;
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值