The Non-virtual Interface (NVI) design pattern is a technique used to encapsulate the public interface of a class behind non-virtual member functions. This pattern is commonly used in C++ to achieve better control over derived class behavior while providing a stable public interface.
The main idea behind the NVI design pattern is to have a public non-virtual member function that serves as an interface to the class's behavior. This non-virtual member function then calls private or protected virtual member functions that provide the actual implementation of the behavior. By doing so, the class can ensure that the behavior is not modified or overridden by derived classes, while still allowing flexibility in modifying the behavior through the use of private or protected virtual functions.
Let's see how this pattern can be implemented in both C++ and C#:
C++ Implementation:
class Base { public: // Public non-virtual interface function void performTask() { // ... Perform some common pre-processing logic ... // Call the private virtual function for the actual implementation doTask(); // ... Perform some common post-processing logic ... } // Destructor (virtual to support polymorphism) virtual ~Base() {} private: // Private virtual function for the actual implementation virtual void doTask() = 0; }; class Derived : public Base { private: // Override the private virtual function for the specific implementation void doTask() override { // ... Specific implementation for Derived ... } };
In C++, the NVI pattern is particularly useful because it allows the base class to control the overall behavior by providing common pre-processing and post-processing steps while leaving the specific implementation details to derived classes.
C# Implementation:
In C#, since methods are non-virtual by default, you don't need to follow the NVI pattern explicitly. However, you can achieve a similar effect by following best practices in design and encapsulation.
public abstract class Base { // Public non-virtual interface method public void PerformTask() { // ... Perform some common pre-processing logic ... // Call the protected virtual method for the actual implementation DoTask(); // ... Perform some common post-processing logic ... } // Protected virtual method for the actual implementation protected virtual void DoTask() { // ... Common implementation ... } } public class Derived : Base { // Override the protected virtual method for the specific implementation protected override void DoTask() { // ... Specific implementation for Derived ... } }
In C#, methods are non-virtual by default, so you can achieve similar encapsulation by making the public method non-virtual and the specific implementation method (DoTask()
in this example) protected and virtual.
Though the NVI pattern is more commonly used in C++, the concepts of separating the public interface from the implementation and allowing customization through protected virtual methods are applicable to both C++ and C#. By following these practices, you can achieve better control over the behavior of your classes and promote maintainability and flexibility in your code.
"Non-virtual interface design pattern C#"
public abstract class MyBaseClass { // Public interface method using NVI pattern public void PublicMethod() { // Non-virtual call to private implementation method PrivateMethod(); } // Private implementation method private void PrivateMethod() { // Implementation details } }
"NVI design pattern benefits in C++"
class MyBaseClass { public: // Public interface method using NVI pattern void PublicMethod() { // Non-virtual call to private implementation method PrivateMethod(); } private: // Private implementation method void PrivateMethod() { // Implementation details } };
"C# NVI pattern vs. abstract class"
// Using abstract class for extensibility public abstract class MyBaseClass { // Abstract method for public interface public abstract void PublicMethod(); }
"Implementing NVI pattern in C++"
class MyBaseClass { public: // Public interface method using NVI pattern void PublicMethod() { // Non-virtual call to private implementation method PrivateMethod(); } private: // Private implementation method virtual void PrivateMethod() { // Implementation details } };
"NVI pattern in C# with inheritance"
public class MyDerivedClass : MyBaseClass { // Overriding the private implementation method protected override void PrivateMethod() { // Custom implementation details for the derived class } }
"C++ NVI pattern and template method"
class MyBaseClass { public: // Public template method using NVI pattern void PublicMethod() { // Non-virtual call to private implementation method PrivateMethod(); } private: // Private virtual implementation method virtual void PrivateMethod() = 0; };
"NVI pattern in C# real-world example"
public class DatabaseAccess { // NVI pattern for executing database operations public void ExecuteQuery(string query) { // Non-virtual call to private implementation method Execute(query); } // Private implementation method private void Execute(string query) { // Implementation details for executing the query } }
"C++ NVI pattern and polymorphism"
class MyBaseClass { public: // Public interface method using NVI pattern void PublicMethod() { // Non-virtual call to private implementation method PrivateMethod(); } private: // Private virtual implementation method virtual void PrivateMethod() { // Implementation details } }; class MyDerivedClass : public MyBaseClass { private: // Overriding the private implementation method void PrivateMethod() override { // Custom implementation details for the derived class } };
"C# NVI pattern and unit testing"
public class MyClass { // NVI pattern for public interface public void PerformOperation() { // Non-virtual call to private implementation method Perform(); } // Private implementation method private void Perform() { // Implementation details } }
"C++ NVI pattern and abstract base class"
class MyBaseClass { public: // Public interface method using NVI pattern void PublicMethod() { // Non-virtual call to private implementation method PrivateMethod(); } private: // Private virtual implementation method virtual void PrivateMethod() = 0; };
kivy express-session uitableview angular2-injection percentile css-tables slider newrelic angularjs-interpolate image-formats