Non Virtual Calls Pure Virtual Idiom

A programming idiom where a non-virtual (Java final) base class method provides a skeleton for an operation by calling pure virtual methods at appropriate points. The base class method contains common code, allows specialization, and enforces correct order of calls. Contrast OverrideAndCallInheritedIdiom.

This is a C++/Java implementation of a TemplateMethodPattern.

The basic idea here is that the base class has a non-virtual or final method which encapsulates the common functionality and enforces the desired contract by calling pure-virtual methods at appropriate points. Working off of the Drawable_Item example from OverrideAndCallInheritedIdiom, we have:

 class Drawable_Item
 {
/** Override item_draw to draw subclass-specific elements. */
void draw(Context context)
{
draw_border(context);
item_draw(context);
update(context);
}

virtual void item_draw(Context context) = 0; };

draw(..) here is not a virtual function, so Drawable_Item::draw(..) is always called through a Drawable_Item pointer/reference. In Java, the method should be declared final. The key point here is that the caller:

  1. Has no choice about which draw(..) gets called and therefore cannot effectively override it.
  2. Must implement item_draw(..)
  3. Does not need to worry about when item_draw(..) is called; it is handled by the superclass.
  4. Does not need to worry about base class refactoring. Since it is being called rather than calling, changes are better isolated and the class is less fragile.

This adds up to a tight and easily testable contract.

-- EricVought


One sometimes gets into a bit of trouble with these methods when they are nested several levels deep. For instance:

 public abstract class Drawable_Item;
 public abstract class Special_Drawable_Item extends Drawable_Item;
 public class My_Special_Drawable_Item extends Special_Drawable_Item;

So, you have draw(..) and item_draw(..) in Drawable_Item. Special_Drawable_Item implements item_draw(..) to handle the code common across all its descendents but wants subclasses to be able to further extend behavior. I split the methods again and create a pure virtual special_item_draw(..) called by Special_Drawable_Item::item_draw(..). In C++, item_draw is already virtual and I can add no further protection --- My_Special_Drawable_Item can maliciously override it and break the contract. In Java, I can declare Special_Drawable_Item.item_draw(..) final. Either way, the common mistakes have been eliminated and there just isn't that much to be done about malice. I find that naming the specialized method after the class (item_draw(..), special_item_draw(..), etc) makes naming much easier in the nested case than variants on _draw, subclass_draw(..) and variants I have seen.

-- EricVought


See also TemplateMethodPattern, OverrideAndCallInheritedIdiom

[ProgrammingIdiom][CeePlusPlusIdioms][JavaIdiom]


CategoryCpp CategoryJava


EditText of this page (last edited April 4, 2008) or FindPage with title or text search