当我们设计面向对象程序时,我们不一定仅是聚焦于virtual函数,其实我们可以有很多的替代方案,每种方式有自己特点和优势。
加入游戏中的人物需要一个函数用以表现任务的健康状态(血量),而游戏中又具有各种不同的角色,因此,我们应该设计一个基类来表示任务角色的相同特征。
相应的,该函数会有一个默认的实现方式。默认方式省略。
事实上,在设计模式中,往往会用其他的方式来替代这种直接方式。
Non-Virtual Interface 方式
这种方式就是将虚函数设计为私有的或者受保护的,然后用一个共有的非虚函数去调用它。
这个方法的的有点在于上述代码中的注释,做一些事前工作,做一些事后工作 , 也就是说我们能够再实际上调用该函数时进行一些准备工作和善后工作 ,诸如获得互斥锁、释放锁等。实际上上述代码并不会影响函数多态特性。
函数指针实现的Strategy模式
上述的方法实际上仅是再virtual函数进行了一些装饰,这样使得我们能够再实现准备和善后的工作。而用函数指针实现的Strategy模式可以实现人物的血量的动态变化。
让每个任务的构造函数接受一个函数指针,这样我们就可以更容易实现动态的改变。
这种方式比之前的方式具有两个更大的优势:
- 同一任务可以又不同的计算方式
- 同一人的血量计算方式可以动态的变更,只需要设置一个函数动态更换相应的函数指针即可
实际上这种方式有一个弊端,如果这种计算方式需要用到人物的其他的私有变量时,我们只能将相应的函数声明为友元函数,按时这将会降低程序的封装性。
由tr1::function完成的Strategy模式
实际上,用函数指针实现Strategy模式只能传入一个函数指针,但是如果我们去用function定义一个可调用类型,这样我们能便能传入更多的可调用对象,而只要这些可调用对象能够转换为我们定义的可调用对象类型即可。
这种方式仅是将函数指针替换为一个可调用的类型。所有可调用对象的类型可以装换为该类型的均能作为血量的计算方式。
这种方式更为灵活,这种方式还能将类的成员函数绑定为计算方式。
古典的Strategy模式
c++设计模式中,经典的Strategy模式是将一个继承体系中的virtual函数替换为另一个继承体系的中的virtual函数,然后再用一个基类的指针指向另一个体系。
对应的代码为: