因为其他的事情耽误了看书,现在将看的笔记记录下来。
1 class GameCharacter {
2 public:
3 virtual int healthValue() const;
4 };
1. 藉由Non-Virtual Interface 手法实现 Template Method模式
(1)non-virtual interface(NVI):
令客户通过public non-virtual 成员函数间接调用private virtual函数
(2) virtual 函数的外覆器(wrapper):non-virtual 函数
1 class GameCharacter {
2 public:
3 int healthValue() const // virtual 函数的外覆器(wrapper)
4 {
5 //...
6 /*
7 做些事前工作:锁定互斥器,制造运转日志记录项,验证class约束条件、验证函数先决条件等等
8 */
9 int retVal = doHealthValue();
10 //...
11 /*
12 做些事后工作:互斥器解除锁定,验证函数的时候条件、再次验证class约束条件等等。
13 */
14 return retVal;
15 }
16 private:
17 virtual int doHealthValue() const
18 {
19 //...
20 }
21 };
优点:
先比于直接调用virtual 函数,就没有任何好办法可以处理事前和时候工作。
注意事项:
重新定义virtual 函数,表示某些事“如何”被完成,“调用virtual 函数”则表示它“何时”被完成。
NVI手法允许derived classs重新定义virtual函数,从而赋予他们“如何实现机能”的控制能力,但base class保留诉说“函数何时被调用”的权利。
2.藉由Function Pointers 实现Strategy模式
1 class GameCharacter; // forward declaration
2
3 int defaultHealthCalc(const GameCharacter& gc); /*计算健康指数的缺省算法*/
4 class GameCharacter {
5 public:
6 typedef int (*HealthCalcFunc) (const GameCharacter&);
7 explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc)
8 :healthFunc(hcf)
9 {}
10
11 int healthValue() const
12 {
13 return healthFunc(*this);
14 }
15 private:
16 HealthCalcFunc healthFunc;
17 };
上述模式的解释说明:
(1)同一任务类型的不同实体可以不同的健康计算函数。e.g:
1 class EvilBadGuy:public GameCharacter {
2 public:
3 explicit EvilBadGuy(HealthCalcFunc hcf = defaultHealthCalc)
4 :GameCharacter(hcf)
5 {
6 //...
7 }
8 };
9
10 int loseHealthQuickly(const GameCharacter&);
11 int loseHealthSlowly(const GameCharacter&);
12
13 /* 相同类型的的人物搭配不同的健康计算方式 */
14 EvilBadGuy ebg1(loseHealthQuickly);
15 EvilBadGuy ebg2(loseHealthSlowly);
(2)某已知人物的健康指数计算函数可在运行期变更。
例如GameCharacter提供一个setHealthCalculator函数,用来替换当前的健康指数计算函数。
(3)一般而言,唯一能够解决“需要以non-member函数访问class的non-public成分”的办法是:弱化class的封装。例如,class可声明那个non-member函数为friends或为其实现的某一部分提供public访问函数。
----> 藉由Function Pointers 实现Strategy模式的缺点是:弱化了class的封装性。
3.藉由tr1::function完成Strategy模式
1 class GameCharacter;
2 int defaultHealthCalc(const GameCharacter& gc);
3 class GameCharacter {
4 public:
5 /*
6 HealthCalcFunc 可以是任何“可调用物”(callable entity),可被调用并接受任何兼容于
7 GameCharacter的事物(参数可被隐式转换为const GameCharacter&),
8 返回任何兼容于int的东西(可被隐式转换为int)。
9
10 类似一个指向函数的泛化指针
11 */
12 typedef std::tr1::function<int (const GameCharacter&)> HealthCalcFunc;
13 explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc)
14 :healthFunc(hcf)
15 {}
16
17 int healthValue() const
18 {
19 return healthFunc(*this);
20 }
21 private:
22 HealthCalcFunc healthFunc;
23
24 };
25
26 /*健康计算函数,注意其返回类型为non-int*/
27 short calcHealth(const GameCharacter&);
28
29 /*为计算健康而设计的函数对象*/
30 struct HealthCalculator {
31 int operator() (const GameCharacter&) const
32 {
33 //...
34 }
35 };
36
37 class GameLevel {
38 public:
39 /*成员函数,用以计算健康;注意其non-int返回类型*/
40 float health(const GameCharacter&) const;
41 //...
42 };
43
44 class EvilBadGuy:public GameCharacter {
45 public:
46 explicit EvilBadGuy(HealthCalcFunc hcf = defaultHealthCalc)
47 :GameCharacter(hcf)
48 {
49 //...
50 }
51 };
52
53 class EyeCandyCharacter:public GameCharacter {
54 public:
55 explicit EyeCandyCharacter(HealthCalcFunc hcf = defaultHealthCalc)
56 :GameCharacter(hcf)
57 {
58 //...
59 }
60 };
61
62 /*使用函数计算健康指数*/
63 EvilBadGuy ebg1(calcHealth);
64 /*使用某个函数对象计算健康指数*/
65 EyeCandyCharacter eccl(HealthCalculator());
66
67 /*使用某个成员函数计算健康指数*/
68 GameLevel currentLevel;
69 EvilBadGuy ebg2(std::tr1::bind(&GameLevel::health, currentLevel, _l));
4.古典的Strategy模式
传统的Strategy做法会将健康计算函数做成一个分离的继承体系中的virtual成员函数
1 class GameCharacter;
2 class HealthCalcFunc {
3 public:
4 //...
5 virtual int calc(const GameCharacter& gc) const
6 {
7 //...
8 }
9 //...
10 };
11
12 HealthCalcFunc defaultHealthCalc;
13 class GameCharacter {
14 public:
15 explicit GameCharacter(HealthCalcFunc* phcf = &defaultHealthCalc)
16 :pHealthCalc(phcf)
17 {}
18
19 int healthValue() const
20 {
21 return pHealthCalc->calc(*this);
22 }
23
24 //...
25 private:
26 HealthCalcFunc *pHealthCalc;
27 };
5.总结
当你为解决问题而寻找某个设计方法时,不妨考虑virtual函数的替代方案。
(1)使用non-vvirtual interface(NVI)手法,它以public non-virtual 成员函数包裹较低
访问性(private或protected)的virtual函数。
(2)将virtual函数替换为“函数指针成员变量”。
(3)以tr1::function 成员变量替换virtual,因而允许使用任何可调用物搭配一个兼容与需求的签名式。
(4)将继承体系内的virtual函数替换为另一个继承体系的virtual函数。
注明:全文文字都是来源《Effective C++》 3th。这里所写都是自己的读书的时候梳理做的笔记罢了。希望对他人有用,那是我的荣幸。
所有内容都是用BSD条款。 Copyright (C) by CloudFeng.