Implementation
In essence, the Template design pattern separates between mandatory primitive operations (which are implemented in the base class) and hooks for customized operations that a subclass may redefine later. Following these guidelines, the modified
Viewer class now looks like this:
class Viewer
{
public:
int Open(const char * filename)
{
init();//mandatory steps: CRC check, authorization
if (is_custimized() )
customized_init();//allow customization by subclasses
}
virtual ~Viewer();
protected: //hooks for a subclass's customizations
virtual bool is_custimized()=0;
virtual void customized_init() {}
private: //mandatory primitive operations
void init();
};
When a subclass overrides a protected member function, it changes that function's
access to private:
class MyViewer: public Viewer
{
//..
private:
bool is_custimized() const;
void customized_init();
}
The Well-Tempered Template
How does it work? A subclass that wishes to retain the base class' functionality as-is shall provide a trivial implementation of
is_customized():
bool is_customized() const {return false;)
When a subclass object calls
Open(), it always executes
Viewer::Open() because this function isn't virtual.
Open() in turn invokes
init() to perform the mandatory primitive operations and then calls the subclass'
is_customized(). A subclass that wishes to customize the behavior of
Open() must change the return value of
is_customized() to true and override
customized_init() as necessary.
A Template Recipe
Let's summarize the design principles of a Template function:
- A Template function is a nonvirtual public member function that performs a series of primitive operations.
- Some of the primitive operations are mandatory; others may be customizable.
- Mandatory operations are nonvirtual private members of the base class.
- Customized primitive operations are declared virtual protected in the base class, but change their access to private in a subclass.
- Customizable primitive operations that must be overridden are declared pure virtual in the base class; those that may be overridden are declared virtual.
In addition to the obvious benefit of providing a skeletal implementation in the base class while allowing a subclass to redefine certain portions thereof, the
Template design pattern minimizes the number of primitive operations that a derived class must perform to flesh out the
Template function. In this example, a derived class merely provides a trivial definition of
is_customizable() to retain the base class functionality.