Two different components have significant similarities, but demonstrate no reuse of common interface or implementation. If a change common to both components becomes necessary, duplicate effort must be expended.
The component designer decides which steps of an algorithm are invariant (or standard), and which are variant (or customizable). The invariant steps are implemented in an abstract base class, while the variant steps are either given a default implementation, or no implementation at all. The variant steps represent “hooks”, or “placeholders”, that can, or must, be supplied by the component’s client in a concrete derived class.
The component designer mandates the required steps of an algorithm, and the ordering of the steps, but allows the component client to extend or replace some number of these steps.
Template Method is used prominently in frameworks. Each framework implements the invariant pieces of a domain’s architecture, and defines “placeholders” for all necessary or interesting client customization options. In so doing, the framework becomes the “center of the universe”, and the client customizations are simply “the third rock from the sun”. This inverted control structure has been affectionately labelled “the Hollywood principle” - “don’t call us, we’ll call you”.
The implementation of template_method()
is: call step_one()
, call step_two()
, and call step_three()
. step_two()
is a “hook” method – a placeholder. It is declared in the base class, and then defined in derived classes. Frameworks (large scale reuse infrastructures) use Template Method a lot. All reusable code is defined in the framework’s base classes, and then clients of the framework are free to define customizations by creating derived classes as needed.
The Template Method defines a skeleton of an algorithm in an operation, and defers some steps to subclasses. Home builders use the Template Method when developing a new subdivision. A typical subdivision consists of a limited number of floor plans with different variations available for each. Within a floor plan, the foundation, framing, plumbing, and wiring will be identical for each house. Variation is introduced in the later stages of construction to produce a wider variety of models.
Abstraction is implemented in Delphi by abstract virtual methods. Abstract methods differ from virtual methods by the base class not providing any implementation. The descendant class is completely responsible for implementing an abstract method. Calling an abstract method that has not been overridden will result in a runtime error.
A typical example of abstraction is the TGraphic
class.
TGraphic
is an abstract class used to implement TBitmap
, TIcon
and TMetafile
. Other developers have frequently used TGraphic
as the basis for other graphics objects such as PCX, GIF, JPG representations. TGraphic
defines abstract methods such as Draw
, LoadFromFile
and SaveToFile
which are then overridden in the concrete classes. Other objects that use TGraphic
, such as a TCanvas
only know about the abstract Draw
method, yet are used with the concrete class at runtime.
Many classes that use complex algorithms are likely to benefit from abstraction using the template method approach. Typical examples include data compression, encryption and advanced graphics processing.
To implement template methods you need an abstract class and concrete classes for each alternate implementation. Define a public interface to an algorithm in an abstract base class. In that public method, implement the steps of the algorithm in calls to protected abstract methods of the class. In concrete classes derived from the base class, override each step of the algorithm with a concrete implementation specific to that class.
This example shows some very simple alogrithm steps, but illustrates the principle of deferring implementation to a subclass.
1: unit Tpl_meth;
2:3: interface
4:5: type
6:7: TAbstractTemplateClass = class(TObject)8: protected9: function Algorithm_StepA: Integer; virtual; abstract;10: function Algorithm_StepB: Integer; virtual; abstract;11: function Algorithm_StepC: Integer; virtual; abstract;12: public13: function Algorithm: Integer;
14: end;
15:16: TConcreteClassA = class(TAbstractTemplateClass)17: protected18: function Algorithm_StepA: Integer; override;
19: function Algorithm_StepB: Integer; override;
20: function Algorithm_StepC: Integer; override;
21: end;
22:23: TConcreteClassB = class(TAbstractTemplateClass)24: protected25: function Algorithm_StepA: Integer; override;
26: function Algorithm_StepB: Integer; override;
27: function Algorithm_StepC: Integer; override;
28: end;
29:30: ...31: