Non-virtual Interface idiome (NVI) 非常不言自明:您不编写public virtual函数,而是编写public调用private virtual实现函数的函数,如下所示:
class Object{
virtual void v_load();
public:
void load(){ v_load(); }
}
这使您(基类作者)能够检查和强制执行前置条件和后置条件或应用其他函数,以便派生类的作者不会忘记它们。
现在,当您是派生作者时,您可能想自己编写一个基类——我们称之为它Pawn——它扩展了 的功能,load()因此必须覆盖v_load(). 但是现在你面临一个问题:
当您覆盖时v_load(),其他想要从您的类派生的客户端将始终覆盖该行为,并且它们不能调用Pawn::v_load(),因为它是一个private函数,它们也不能调用,Pawn::load()因为它被定义为{ v_load; }其中Object当然会导致无限循环. 此外,当他们忘记那个电话时,要求他们这样做可能会导致错误。如果我希望他们启用它,我将不得不指定对v_load()as protectedin的访问权限Object,这似乎是一个丑陋的解决方案,因为它会Object大大削弱 的封装。
当然,您仍然可以覆盖v_load()以调用新函数v_pawnLoad(),然后由客户端覆盖,但这似乎很容易出错,因为许多客户端可能会重载错误的函数。
那么,我如何设计Pawn这样一种方式,即客户端仍然可以覆盖v_load(),同时保持检查前置条件或调用其他函数的能力,并且(如果可能)不启用,更不用说要求客户端Object或Pawn调用基本v_load()实现了?