9

NVI(非虚拟接口)和模板方法模式有什么区别?

它们看起来非常相似,我读过它们基本上是相同的,并且它们之间存在细微的差异,因为 Template 更普遍。

4

2 回答 2

15

NVI是一个成语,Template Method是一个模式。NVI 是在 C++ 中使用动态调度的模板方法模式的实现;也可以使用模板元编程在 C++ 中创建模板方法来消除动态分派。

模式比惯用语更通用,语言可能使用不同的惯用语来实现模式。

于 2010-06-20T10:11:35.990 回答
11

如前所述,NVI 是一种编程习语,与一类语言有关。它由 Herb Sutter 等人推广,因为它有助于执行合同:

  • 类不变量
  • 函数契约(对传递的参数和生成的返回值的断言)
  • 重复操作(如日志记录)
  • 控制生成的异常(虽然是个坏主意;))

然而,实现实际上可能有很大不同,例如 NVI 实现的另一个例子是将它与 Pimpl 结合起来:

class FooImpl;

class Foo
{
public:
  enum type { Type1, Type2 };

  Foo(type t, int i, int j);

  int GetResult() const;

private:
  FooImpl* mImpl;
};

对于实施:

struct FooImpl
{
  virtual ~FooImpl();
  virtual int GetResult() const;
};

class FooType1: public FooImpl
{
public:
  FooType1(int i, int j);
  virtual int GetResult() const;
private:
  /// ...
};

我一直发现它更好地传达了这一点。你想通了吗?

重点是virtual实现细节。在接口中公开实现细节是一个坏主意,因为您可能希望更改它们。

此外,实现细节往往会混淆二进制兼容性。例如virtual,在一个类中添加一个新方法可能会改变虚拟表的布局(常见的实现技术),从而破坏二进制兼容性。在 gcc 上,如果您希望保持兼容性,您需要确保最后添加它(在虚拟中)。

通过使用上面的 NVI + Pimpl 组合,virtual暴露的类中根本没有(甚至不是私有的)。内存布局向后和向前兼容。我们已经实现了二进制兼容性。

在这里,我们一次使用几种模式:

  • 模板法
  • 策略(因为我们可以随意交换指针)
  • 工厂(决定我们得到哪个实现)
于 2010-06-20T11:11:47.343 回答