Over the years, one technique has found a cosy corner in my bag of tricks, it gets used reasonably regularly, yet everyone whom I talk to about it has absolutely no idea what it is. Although I can guarantee that pretty much everyone has either unwittingly used it, or used and interface which has been implemented using it.
The technique in question is the Non Virtual Interface (NVI).
A simple example of the technique would be:
class Interface
{
public:
// publicly accessible interface
void Execute()
{
InternalExecute();
}
private:
// private function which will be overridden by specialisation
virtual void InternalExecute()
{
// do work
}
};
class InterfaceChild : public Interface
{
private:
virtual void InternalExecute()
{
// do work specific to this class.
}
};
Here we see that the interface class implements a public interface with a single entry point “Execute”. The Execute function calls a privately declared virtual function called “InternalExecute”. This enforces that any class which inherits from our “Interface” will only be able to provide a specialised version of the “InternalExecute” function, and not the interface itself, keeping the interface consistent across all specialisations of our base “Interface”.
Keeping the interface consistent, and limiting the scope of what can be overridden helps to keep the code focused, and helps enforce the original intention and direction of the interface onto child implementations.
This is also a useful technique for when you wish to execute code before, and/or after the virtual function call. In an interface which uses public virtual functions, we end up replicating the pre/post-amble code throughout each virtual function override, however using NVI, we can place this common code directly before we call the private virtual function which specialisations override. For example, we may wish to implement a naive form of thread synchronisation around our private virtual call, this can be achieved by the following:
void Interface::Execute()
{
//preamble
// Eg: naive critical section / semaphore lock
InternalExecute();
//post amble
// Eg: naive critical section / semaphore unlock.
}
So, next time you’re designing an interface, consider whether you really need to place your virtual functions in the interface itself. Can you hide the implementation from the outside world? If so, NVI is for you!