C++: Difference between NVI and Template Method Patterns?
What is the difference between NVI ( Non-Virtual Interface ) and the Template Method patterns?
They seem very similar and I've read both that they're basically the same and that they're subtly different with Template being somehow m开发者_运维知识库ore general.
NVI is an idiom, Template Method is a pattern. NVI is an implementation of the Template Method Pattern using dynamic dispatch in C++; it is also possible to create template methods in C++ using template metaprogramming to eliminate the dynamic dispatch.
A pattern is more general than an idiom, and languages may use different idioms to implement the pattern.
As has been said, NVI is a progamming idiom, related to a category of languages. It's been promoted by Herb Sutter among others, because it helps enforcing contracts:
- class invariants
- function contracts (assertions over the parameters passed and the return value generated)
- repetitive operations (like logging)
- control over the exceptions generated ( bad idea though ;) )
However, the implementation may actually differ considerably, for example another example of NVI implementation is to combine it with Pimpl:
class FooImpl;
class Foo
{
public:
enum type { Type1, Type2 };
Foo(type t, int i, int j);
int GetResult() const;
private:
FooImpl* mImpl;
};
And for the implementation:
struct FooImpl
{
virtual ~FooImpl();
virtual int GetResult() const;
};
class FooType1: public FooImpl
{
public:
FooType1(int i, int j);
virtual int GetResult() const;
private:
/// ...
};
I've always found that it conveyed the point better. Have you figured it out ?
The main point is that virtual
is an implementation detail. And exposing implementation details in the interface is a bad idea, because you may wish to change them.
Furthermore implementation details tend to mess with binary compatibility. For example adding a new virtual
method in a class may change the layout of the virtual table (common implementation technic) and thus botch the binary compatibility. On gcc you need to make sure that you add it last (among the virtual) if you wish to preserve the compatibility.
By using the NVI + Pimpl combination above, there is no virtual
at all (not even private) in the class exposed. The memory layout is backward and forward compatible. We have achieve binary compatibility.
Here, we use several patterns at once:
- Template Method
- Strategy (since we can swap the pointer at will)
- Factory (to decide which implementation we get)
精彩评论