template


 * Course:** SSE658
 * Project:** 3
 * Subject:** Template Method Pattern
 * Student:** Dmitriy Slipak
 * E-mail:** dslipak@gmail.com

=Table Of Content=

Definition Classification Intent Motivation Applicability Structure Participants Advantages Disadvantages Implementation Example Conclusion References

 =Definition=

A template method is an abstract definition of an algorithm. It defines the algorithm step by step. Each step invokes either an abstract operation or a primitive operation. A subclass fleshes out the algorithm by defining the abstract operations.

The template method pattern is a Gang of Four design pattern. This is a behavioral pattern as it defines a manner for controlling communication between classes or entities. The template method pattern is used to define the basic steps of an algorithm and allow the implementation of the individual steps to be changed. This is similar to the strategy design pattern. The key difference is the ability to vary parts of the algorithm rather than replacing the algorithm in its entirety.

The overall structure of the basic algorithm is defined in an abstract base class. This class may include some real functionality but often just defines the order in which the overridable steps will be executed. The implementations for the steps are defined in subclasses. This use of inheritance promotes loose coupling, as the calling function need not know which algorithm is to be executed. Correct use of the pattern also reduces duplication of code.  =Classification=

Object Behavioral Pattern.  =Intent=

Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.  =Motivation=

Average application, designed in object-oriented manner, contains number of classes. There could be a situation, when few classes similar in their basic algorithm (for example the same sequence of operations), but in details, they perform different things. The idea behind the Template pattern is that some parts of an algorithm are well defined and can be implemented in the base class, while other parts may have several implementations and are best left to derived classes. Another main theme is recognizing that there are some basic parts of a class that can be factored out and put in a base class so that they do not need to be repeated in several subclasses.  =Applicability=

The Template Method pattern should be used in following situations:


 * When there is a need to implement the invariant parts of an algorithm once and leave it up to subclasses to implement the behavior that can vary.


 * When common behavior among subclasses should be factored and localized in a common class to avoid code duplication. In this case we first identify the differences in the existing code and then separate the differences into new operations. Finally, we replace the differing code with a template method that calls one of these new operations.

 =Structure=
 * When there is a need to control subclasses extensions. We can define a template method that calls “hook” operations at specific points, thereby permitting extensions only at those points.

 =Participants=


 * **Abstract Class** - defines abstract primitive operations that concrete subclasses define to implement steps of an algorithm. Implements a template method defining the skeleton of an algorithm. The template method calls primitive operations as well as operations defined in Abstract Class or those of other objects.

 =Advantages=
 * **Concrete Class** - implements the primitive operations to carry out subclass-specific steps of the algorithm.


 * **Code reuse**. Template methods are a fundamental technique for code reuse. They are particularly important in class libraries, because they are the means for factoring out common behavior in library classes.


 * **Inverted Control Structure**. Template methods lead to an inverted control structure that's sometimes referred to as "the Hollywood principle", that is, "Don't call us, we'll call you". This refers to how a parent class calls the operations of a subclass and not the other way around.

> Template methods call the following kinds of operations:


 * 1) Concrete operations (either on the Concrete Class or on client classes).
 * 2) Concrete Abstract Class operations (i.e., operations that are generally useful to subclasses).
 * 3) Primitive operations (i.e., abstract operations).
 * 4) Factory methods.
 * 5) Hook operations, which provide default behavior that subclasses can extend if necessary. A hook operation often does nothing by default.

> It's important for template methods to specify which operations are hooks (may be overridden) and which are abstract operations (must be overridden). To reuse an abstract class effectively, subclass writers must understand which operations are designed for overriding.  =Disadvantages=

As a disadvantages for a Template Method pattern following could be considered:

 =Implementation=
 * Communicates intent poorly
 * Difficult to compose functionality.
 * Difficult to comprehend program flow.
 * Difficult to maintain.

Following should be considered during the Template Method implementation:


 * **Using C++ access control**. In C++, the primitive operations that a template method calls can be declared protected members. This ensures that they are only called by the template method. Primitive operations that must be overridden are declared pure virtual. The template method itself should not be overridden; therefore you can make the template method a non virtual member function.


 * **Minimizing primitive operations**. An important goal in designing template methods is to minimize the number of primitive operations that a subclass must override to flesh out the algorithm. The more operations that need overriding, the more tedious things get for clients.

 =Example=
 * **Naming conventions**. We can identify the operations that should be overridden by adding a prefix to their names.

The example below demonstrates "Template Method" pattern implementation. Here, **Transport** is abstract class. **Airplane**, **Boat**, and **Truck** are derived classes from the **Transport** class. The **Transport** class contains "**add_cargo**" function which is a template method. "**add_cargo**" function defines a simple cargo handling algorithm. It also demonstrates the "Hollywood principle", when base class calls operations in derived classes.

code format="C++" // Module:       template.h // Programmer:    Dmitriy Slipak // Date:       February 22, 2010 // Purpose:       Header file, contains classes declaration //               to illustrate Template Method pattern //
 * Module:** template.h
 * 1) ifndef _TEMPLATE_H_
 * 2) define _TEMPLATE_H_


 * 1) include
 * 2) include

//   set of cargo measurement constants const float MAX_AIRPLANE_CARGO_WIDTH = 200.0; const float MAX_AIRPLANE_CARGO_HEIGHT = 100.0; const float MAX_AIRPLANE_CARGO_WEIGHT = 10000.0;

const float MAX_BOAT_CARGO_WIDTH = 60.0; const float MAX_BOAT_CARGO_HEIGHT = 50.0; const float MAX_BOAT_CARGO_WEIGHT = 5000.0;

const float MAX_TRUCK_CARGO_WIDTH = 20.0; const float MAX_TRUCK_CARGO_HEIGHT = 10.0; const float MAX_TRUCK_CARGO_WEIGHT = 2000.0;

//   cargo structure declaration //   simple structure to handle a cargo struct Cargo {   float width; float height; float weight; };

//   abstract data type Transport declaration class Transport { private: std::vector* trunk;

void load_cargo(Cargo& cargo);   //    primitive operation

protected: void secure_by_fasteners(Cargo& cargo);   //    primitive operation void secure_by_dunnage(Cargo& cargo);   //    primitive operation void secure_by_strap(Cargo& cargo);   //    primitive operation

public: Transport; ~Transport;

void add_cargo(Cargo& cargo);   //    template method virtual bool check_cargo(Cargo& cargo) = 0;   //    primitive operation (hook or placeholder) virtual void secure_cargo(Cargo& cargo) = 0;   //    primitive operation (hook or placeholder) };

//   Airplane class declaration class Airplane : public Transport { public: bool check_cargo(Cargo& cargo);       //    hook or placeholder override void secure_cargo(Cargo& cargo);   //    hook or placeholder override };

//   Boat class declaration class Boat : public Transport { public: bool check_cargo(Cargo& cargo);       //    hook or placeholder override void secure_cargo(Cargo& cargo);   //    hook or placeholder override };

//   Truck class declaration class Truck : public Transport { public: bool check_cargo(Cargo& cargo);       //    hook or placeholder override void secure_cargo(Cargo& cargo);   //    hook or placeholder override };

code
 * 1) endif

code format="C++" // Module:       template.cpp // Programmer:   Dmitriy Slipak // Date:       February 22, 2010 // Purpose:       Classes implementation file //               to illustrate Template Method pattern //
 * Module:** template.cpp
 * 1) include "template.h"

/// ///   Transport class implementation ///

//   default constructor Transport::Transport {   trunk = new std::vector; };

//   default destructor Transport::~Transport {   delete trunk; }

//   template method, contains a simple cargo handling algorithm //   both, check_cargo and secure_cargo functions calls are examples //   of the "Hollywood principle" void Transport::add_cargo(Cargo& cargo) {   if (!check_cargo(cargo)) {    //    check a cargo measurement ("Hollywood principle") std::cout << "can't handle cargo\n"; return; }

load_cargo(cargo);   //    put a cargo into trunk secure_cargo(cargo);   //    handle a cargo ("Hollywood principle") }

//   primitive operation, no overriding in subclasses void Transport::load_cargo(Cargo& cargo) {   trunk->push_back(cargo); }

//   primitive operation, no overriding in subclasses void Transport::secure_by_fasteners(Cargo& cargo) { std::cout << "the cargo secured by fasteners\n"; } //   primitive operation, no overriding in subclasses void Transport::secure_by_dunnage(Cargo& cargo) { std::cout << "the cargo secured by dunnage\n"; } //   primitive operation, no overriding in subclasses void Transport::secure_by_strap(Cargo& cargo) { std::cout << "the cargo secured by strap\n"; }

/// ///   Airplane class implementation ///

//   Base class primitive operation override bool Airplane::check_cargo(Cargo& cargo) {   if (cargo.height > MAX_AIRPLANE_CARGO_HEIGHT) return false; if (cargo.width > MAX_AIRPLANE_CARGO_WIDTH) return false; if (cargo.weight > MAX_AIRPLANE_CARGO_WEIGHT) return false;

return true; }

//   Base class primitive operation override void Airplane::secure_cargo(Cargo& cargo) {   secure_by_fasteners(cargo);    //    base class primitive operation call }

/// ///   Boat class implementation ///

//   Base class primitive operation override bool Boat::check_cargo(Cargo& cargo) {   if (cargo.height > MAX_BOAT_CARGO_HEIGHT) return false; if (cargo.width > MAX_BOAT_CARGO_WIDTH) return false; if (cargo.weight > MAX_BOAT_CARGO_WEIGHT) return false;

return true; }

//   Base class primitive operation override void Boat::secure_cargo(Cargo& cargo) {   secure_by_dunnage(cargo);    //    base class primitive operation call }

/// ///   Truck class implementation ///

//   Base class primitive operation override bool Truck::check_cargo(Cargo& cargo) {   if (cargo.height > MAX_TRUCK_CARGO_HEIGHT) return false; if (cargo.width > MAX_TRUCK_CARGO_WIDTH) return false; if (cargo.weight > MAX_TRUCK_CARGO_WEIGHT) return false;

return true; }

//   Base class primitive operation override void Truck::secure_cargo(Cargo& cargo) {   secure_by_strap(cargo);    //    base class primitive operation call } code

code format="C++"
 * Module:** template_driver.cpp
 * 1) include "template.h"

int main {    //    test template method Cargo cargo = {200.0, 100.0, 9000.0};   //    cargo for an airplane

std::cout << "***Airplane\n"; Transport* transport = new Airplane; transport->add_cargo(cargo);   //    template method call delete transport;

//   redefine cargo for a boat cargo.height = 30.0; cargo.width = 40.0; cargo.weight = 2000.0;

std::cout << "\n***Boat\n"; transport = new Boat; transport->add_cargo(cargo);   //    template method call delete transport;

//   redefine cargo for a truck cargo.height = 5.0; cargo.width = 10.0; cargo.weight = 1500.0;

std::cout << "\n***Truck\n"; transport = new Truck; transport->add_cargo(cargo);   //    template method call delete transport;

return 0; } code

Test run produces following result Complete source code for this example can be located at the course FTP server, in the folder under my name.  =Conclusion=

The template method patten is relatively easy in implementation and useful in various situations. This makes the template method pattern as an important addition to software design and development tools set.  =References=

Last revision date: {$revisiondate}