Back to results for “Interfaces & Abstract Classes”
Java › Interfaces & Abstract Classes

How would you use an abstract class combined with the Non-Virtual Interface (NVI) idiom to enforce that certain methods are always called in a specific pattern, even when subclasses override customizable parts?

Advanced

Answer

The NVI idiom involves making a class's PUBLIC entry-point methods non-overridable (final, or in an abstract class's case, a concrete final method), while the actual customizable behavior is exposed only through PRIVATE or PROTECTED virtual (overridable) methods that the public method internally calls -- this guarantees that any pre/post logic, validation, or invariant-checking in the public method ALWAYS executes regardless of what a subclass does in its override, since subclasses have no ability to bypass the public entry point and directly access the internal virtual methods from outside the class, combining encapsulation with guaranteed structural behavior in a way that's stronger than simply documenting 'please call super() first' convention-based approaches.
public abstract class Transaction {
    public final boolean execute() {  // NVI: public entry point, NOT overridable
        if (!validate()) return false;
        boolean result = performTransaction();  // customizable via the protected virtual method
        logResult(result);
        return result;
    }
    protected abstract boolean performTransaction();  // the ONLY thing subclasses actually customize
    private boolean validate() { return true; }        // always runs, subclasses cannot skip or bypass it
    private void logResult(boolean result) { System.out.println("Result: " + result); }
}
Real-world example A financial transaction processing framework guarantees that validation and logging ALWAYS occur around every transaction execution (regardless of what any specific transaction subtype's performTransaction() override does), by structuring the class using NVI so subclasses can only customize the actual transaction logic itself, never bypass or reorder the surrounding validation/logging guarantees.

Common follow-ups: How does this NVI-based guarantee compare in robustness to simply documenting that subclasses 'must call super.execute() first', a convention subclasses could accidentally violate?;What's the relationship between this pattern and the earlier-discussed Template Method pattern?