我們考慮下面這個問題:假設我們在開發一款遊戲,遊戲中有不同的角色,每個角色有自己的生命值的初始值,生命值的計算方法等等。你會怎麼設計這個類呢?我們很自然的就會想到:
class gamecharacter
;
就是說基類裡定義了乙個計算生命值的函式,派生類通過重新定義這個函式來完成不同型別的角色的生命值的計算。
假如生命值的計算分為如下幾步:
1.獲得生命值。
2.通過乙個函式計算生命值。
3.將生命值返回。
那麼每個派生類的healthvalue函式都需要完成這幾步,我們能不能重構這個**呢?先看一下重構的結果:
class gamecharacter
protected:
virtual int getinitialval() = 0;
virtual int calcval(int ) = 0;
};class soldier:public gamecharacter
;class patient:public gamecharacter
;//戰士的初始生命值較高
int soldier::getinitialval()
//但是生命值會減半
int soldier::calcval(int val)
//病人的宣告值較低
int patient::getinitialval()
//但是生命值會翻倍
int patient::calcval(int val)
這種做法乍看起來不是很習慣,我們要對它的思路仔細說說:
1.它在基類中宣告了2個不會被繼承的虛函式getinitialval()和calcval(int val)。但是在基類的可以被繼承的(且不希望被修改的)healthvalue函式中呼叫了。
2.在派生類中定義了healthvalue所要呼叫的函式。
他這樣做的好處是:在基類中,限定了先做什麼,後做什麼。但是具體怎樣做,把權力移交給了派生類。
這種思路,稱為模板方法模式,它的定義為:定義乙個操作中的演算法的骨架,而將一些方法實現延遲到子類。模板方法使得子類可以不改變乙個演算法的結構即可以重定義該演算法的某些特定步驟。
但是這樣做其實並不靈活,假如我希望同乙個型別的不同物件有不同的計算生命值的方法,就麻煩了。換個角度思考,人物健康指數的計算,其實,不一定與人物的特定型別有關,對於同乙個型別,也可以有不同的計算方法。由此我們想到,不能讓每個型別的宣告計算與乙個函式相關,而對於不同的物件,可以呼叫不同的函式來完成這件事。依照這個思路,我們可以這麼寫:
//人物健康指數的計算與人物型別無關
//要求每個人物的建構函式接受乙個指標,指向乙個健康計算函式
class gamecharacter;
int defaulthealthcalc(const gamecharacter& gc);
class gamecharacter
int healthvalue()const
virtual int getinithealth()const = 0;
private:
healthcalcfunc healthfunc;
};class soldier:public gamecharacter
int getinithealth()const;
};class patient:public gamecharacter
int getinithealth()const;
};int losehealthquickly(const gamecharacter&);
int losehealthslowly(const gamecharacter&);
int recoverhealth(const gamecharacter&);
int soldier::getinithealth()const
int patient::getinithealth()const
int defaulthealthcalc(const gamecharacter& gc)
int losehealthquickly(const gamecharacter& gc)
int losehealthslowly(const gamecharacter& gc)
int recoverhealth(const gamecharacter& gc)
此時,人物型別與計算宣告的方法就無關了:
int main()
int healthvaule()const
virtual int getinithealth()const = 0;
private:
healthcalcfunc healthfunc;
};class soldier:public gamecharacter
int getinithealth()const;
};//可以採取以下3種措施呼叫計算健康值的函式
//計算健康值的函式,其返回型別為short
short halfhealth(const gamecharacter&);
//計算健康值的函式物件
struct addhealth
;//計算生命值方法派生類
class addhealth:public healthcalcfunc
;//計算生命值方法派生類
class doublehealth:public healthcalcfunc
;//標頭檔案中宣告
extern healthcalcfunc defaulthealthcalc;
#include "healthcalcfunc.h"
#include "gamecharacter.h"
int healthcalcfunc::calc(const gamecharacter& gc)const
int gamecharacter::getinithealth()const
int main()
{ gamecharacter gc0;
cout<
條款35 考慮virtual函式以外的其他選擇
大多時候,我們會自然而然的想到使用virtual手法來塑模現實中的類。但是,實際上也有別的方案可以替代virtual手法的,即 考慮virtual函式以外的其他選擇。下面介紹的便是幾種可以替代virtual的方案。1 non virtual inte ce 是template method 設計模式...
考慮Virtual函式以外的其他選擇
方法一,基於虛函式的方法 在人物角色的基類增加乙個成員函式heathvalue,返回乙個整數,表示人物的健康程度,並將宣告為virtual 1 class gamecharacter heathvalue宣告為虛函式,因而派生類可以重新定義它,從而獲得達到不同的人物可能不同的方式計算他們的健康指數的...
C 考慮virtual函式以外的其他選擇
方法一,基於虛函式的方法 在人物角色的基類增加乙個成員函式heathvalue,返回乙個整數,表示人物的健康程度,並將宣告為virtual 1 class gamecharacter heathvalue宣告為虛函式,因而派生類可以重新定義它,從而獲得達到不同的人物可能不同的方式計算他們的健康指數的...