Non-virtual interface pattern
The non-virtual interface pattern (NVI) controls how methods in a base class are overridden. Such methods may be called by clients and overridable methods with core functionality.[1] It is a pattern that is strongly related to the template method pattern. The NVI pattern recognizes the benefits of a non-abstract method invoking the subordinate abstract methods. This level of indirection allows for pre and post operations relative to the abstract operations both immediately and with future unforeseen changes. The NVI pattern can be deployed with very little software production and runtime cost. Many commercial software frameworks employ the NVI pattern.
Benefits and detriments
A design that adheres to this pattern results in a separation of a class interface into two distinct interfaces:
- Client interface: This is the public non-virtual interface
- Subclass interface: This is the private interface, which can have any combination virtual and non-virtual methods.
With such a structure, the fragile base class interface problem is mitigated. The only detriment is that the code is enlarged a little.[2]
C# Example
namespace Shell
{
public class Node<TData>
{
public TData Data { get; set; }
public Node<TData> Next { get; set; }
public Node() { }
public Node(TData data)
{
Data = data;
}
public override string ToString()
{
return Data.ToString();
}
}
public class DoubleNode<TData>: Node<TData>
{
public new DoubleNode <TData> Next { get; set; }
public DoubleNode <TData> Previous { get; set; }
public DoubleNode () { }
public DoubleNode (TData data): base(data) {}
}
public class LinkedList<TData, TNode> where TNode: Node<TData>
{
public TNode Head { get; internal set; }
public TNode Tail { get; internal set; }
public LinkedList()
{
Head = Tail = null;
}
// Non virtual interface pattern
// We define `protected virtual` methods that contain the variant implementations of the linked list API.
// The invariant processing necessary for the API is implemented in our `public` methods.
// The variant processing necessary to implement the API can be implemented by the derived classes in the hook methods.
protected virtual void VariantAddHeadNode(TNode newHead) { }
public void AddHeadNode(TNode newHead)
{
if (Head is null)
Tail = newHead;
else
{
VariantAddHeadNode(newHead);
newHead.Next = Head;
}
Head = newHead;
}
}
public class DoublyLinkedList<TData>: LinkedList<TData, DoubleNode<TData>>
{
public DoublyLinkedList(): base() {}
// The variant processing necessary to implement the API in a doubly linked list.
protected override void VariantAddHeadNode(DoubleNode<TData> newHead)
{
Head.Previous = newHead;
}
}
}
See also
References
- ^ Carr, Richard (2011-09-03). "Non-Virtual Interface Design Pattern". BlackWasp. Archived from the original on 2011-09-03. Retrieved 2012-09-12.
The non-virtual interface pattern is a design pattern that controls how methods in a base class are overridden. Base classes include public, non-virtual members that may be called by clients and a set of overridable methods containing core functionality.
- ^ Tambe, Sumant (2007-04-11). "Non-Virtual Interface (NVI) idiom and the design intent". C++ truths. Archived from the original on 2007-04-11. Retrieved 2012-09-12.