Non-virtual interface pattern: Difference between revisions

Content deleted Content added
Added a C# example of the pattern.
C# example: add image
 
(4 intermediate revisions by 2 users not shown)
Line 31:
}}</ref>
 
=== C# Exampleexample ===
// [[File:Non -virtual interface pattern.svg]]
 
<syntaxhighlight lang="c#" line="1">
public abstract class Saveable
namespace Shell
{
// The invariant processing necessary for the APImethod is implementeddefined in ourthe non `public`virtual methodsinterface.
public class Node<TData>
// The behaviour so defined is inherited by all derived classes.
// For example, creating and committing a transaction.
public classvoid Node<TData>Save()
{
Console.WriteLine("Creating transaction");
public TData Data { get; set; }
{CoreSave();
public Node<TData> Next { get; set; }
Console.WriteLine("Committing transaction");
 
public Node() { }
public Node(TData data)
{
Data = data;
}
 
public override string ToString()
{
return Data.ToString();
}
}
 
// The variant processing necessaryfor tothe implementmethod theis APIdefined in a doublythe linkedsubclass listinterface.
public class DoubleNode<TData>: Node<TData>
// This behaviour can be customised as needed by subclasses.
// For example the specific implementation of saving data to the database.
protected abstract void CoreSave();
}
public class Customer : Saveable
{
public TDatastring DataName { get; set; }
public Node<TData>decimal NextCredit { get; set; }
publicprotected override stringvoid ToStringCoreSave()
{
Console.WriteLine($"Saved customer {Name} with credit limit {Credit}");
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;
}
}
}
</syntaxhighlight><ref>{{Cite web|title=Non-Virtual Interface Design Pattern|url=http://www.blackwasp.co.uk/nvi.aspx|access-date=2021-09-19|website=www.blackwasp.co.uk}}</ref><ref>{{Cite web|title=Non-Virtual Interface Design Pattern (Page 2 of 2)|url=http://www.blackwasp.co.uk/nvi_2.aspx|access-date=2021-09-19|website=www.blackwasp.co.uk}}</ref>
</syntaxhighlight>
 
== See also ==