Template method pattern: Difference between revisions
mNo edit summary |
→Overview: hyphen |
||
(27 intermediate revisions by 22 users not shown) | |||
Line 1: | Line 1: | ||
{{Short description|Behavioral design pattern in object-oriented programming}} |
|||
{{distinguish|Template processor}} |
{{distinguish|Template processor}} |
||
{{multiple issues| |
|||
{{more footnotes|date=March 2012}} |
{{more footnotes|date=March 2012}} |
||
{{expert needed|date=May 2016}} |
|||
}} |
|||
In [[object-oriented programming]], the '''template method''' is one of the [[behavioral pattern|behavioral]] [[Software design pattern|design patterns]] identified by Gamma et al.<ref name=":0">{{cite book|title=Design Patterns|last1=Gamma|first1=Erich|last2=Helm|first2=Richard|last3=Johnson|first3=Ralph|last4=Vlissides|first4=John|publisher=Addison-Wesley|year=1994|isbn=0-201-63361-2|pages=[https://archive.org/details/designpatternsel00gamm/page/325 325–330]|chapter=Template Method| |
In [[object-oriented programming]], the '''template method''' is one of the [[behavioral pattern|behavioral]] [[Software design pattern|design patterns]] identified by Gamma et al.<ref name=":0">{{cite book|title=Design Patterns|last1=Gamma|first1=Erich|last2=Helm|first2=Richard|last3=Johnson|first3=Ralph|last4=Vlissides|first4=John|publisher=Addison-Wesley|year=1994|isbn=0-201-63361-2|pages=[https://archive.org/details/designpatternsel00gamm/page/325 325–330]|chapter=Template Method|author-link1=Erich Gamma|author-link2=Richard Helm|author-link3=Ralph Johnson (computer scientist)|author-link4=John Vlissides|title-link=Design Patterns}}</ref> in the book ''[[Design Patterns]]''. The template method is a method in a superclass, usually an abstract superclass, and defines the skeleton of an operation in terms of a number of high-level steps. These steps are themselves implemented by additional ''helper methods'' in the same class as the ''template method''. |
||
The ''helper methods'' may be either ''[[ |
The ''helper methods'' may be either ''[[abstract method]]s'', in which case subclasses are required to provide concrete implementations, or ''[[hook methods]],'' which have empty bodies in the superclass. [[Subclass (computer science)|Subclass]]es can (but are not required to) customize the operation by [[Method overriding|overriding]] the hook methods. The intent of the template method is to define the overall structure of the operation, while allowing subclasses to refine, or redefine, certain steps.<ref name=":2">{{cite book|url=http://shop.oreilly.com/product/9780596007126.do|title=Head First Design Patterns|last2=Freeman|first2=Elisabeth|last3=Sierra|first3=Kathy|last4=Bates|first4=Bert|publisher=O'REILLY|year=2004|isbn=978-0-596-00712-6|editor-last=Hendrickson|editor-first=Mike|volume=1|pages=289, 311|format=paperback|editor-last2=Loukides|editor-first2=Mike|last1=Freeman|first1=Eric|access-date=2012-09-12}}</ref> |
||
==Overview== |
==Overview== |
||
Line 14: | Line 12: | ||
* The "template method" is implemented as a method in a [[base class]] (usually an [[abstract class]]). This method contains code for the parts of the overall algorithm that are invariant. The template ensures that the overarching algorithm is always followed.<ref name=":0" /> In the template method, portions of the algorithm that may ''vary'' are implemented by sending self messages that request the execution of additional ''helper'' methods. In the base class, these helper methods are given a default implementation, or none at all (that is, they may be abstract methods). |
* The "template method" is implemented as a method in a [[base class]] (usually an [[abstract class]]). This method contains code for the parts of the overall algorithm that are invariant. The template ensures that the overarching algorithm is always followed.<ref name=":0" /> In the template method, portions of the algorithm that may ''vary'' are implemented by sending self messages that request the execution of additional ''helper'' methods. In the base class, these helper methods are given a default implementation, or none at all (that is, they may be abstract methods). |
||
* Subclasses of the base class "fill in" the empty or "variant" parts of the "template" with specific algorithms that vary from one subclass to another.<ref name=":1" /> It is important that subclasses do ''not'' override the template method itself. |
* Subclasses of the base class "fill in" the empty or "variant" parts of the "template" with specific algorithms that vary from one subclass to another.<ref name=":1" /> It is important that subclasses do ''not'' override the ''template method'' itself. |
||
At run-time, the algorithm represented by the template method is executed by sending the template message to an instance of one of the concrete subclasses. Through inheritance, the template method in the base class starts to execute. When the template method sends a message to self requesting one of the helper methods, the message will be received by the concrete sub-instance. If the helper method has been overridden, the overriding implementation in the sub-instance will execute; if it has not been overridden, the inherited implementation in the base class will execute. This mechanism ensures that the overall algorithm follows the same steps every time |
At run-time, the algorithm represented by the template method is executed by sending the template message to an instance of one of the concrete subclasses. Through inheritance, the template method in the base class starts to execute. When the template method sends a message to self requesting one of the helper methods, the message will be received by the concrete sub-instance. If the helper method has been overridden, the overriding implementation in the sub-instance will execute; if it has not been overridden, the inherited implementation in the base class will execute. This mechanism ensures that the overall algorithm follows the same steps every time while allowing the details of some steps to depend on which instance received the original request to execute the algorithm. |
||
This pattern is an example of [[inversion of control]] because the high-level code no longer determines what algorithms to run; a lower-level algorithm is instead selected at run-time. |
This pattern is an example of [[inversion of control]] because the high-level code no longer determines what algorithms to run; a lower-level algorithm is instead selected at run-time. |
||
Some of the self |
Some of the self-messages sent by the template method may be to ''hook methods.'' These methods are implemented in the same base class as the template method, but with empty bodies (i.e., they do nothing). Hook methods exist so that subclasses can override them, and can thus fine-tune the action of the algorithm ''without'' the need to override the template method itself. In other words, they provide a "hook" on which to "hang" variant implementations. |
||
== Structure == |
== Structure == |
||
=== UML class diagram === |
=== UML class diagram === |
||
[[File:w3sDesign Template Method Design Pattern UML.jpg|frame|none|A sample UML class diagram for the Template Method design pattern.<ref>{{cite web|title=The Template Method design pattern - Structure |url=http://w3sdesign.com/?gr=b10&ugr=struct|website=w3sDesign.com| |
[[File:w3sDesign Template Method Design Pattern UML.jpg|frame|none|A sample UML class diagram for the Template Method design pattern.<ref>{{cite web|title=The Template Method design pattern - Structure |url=http://w3sdesign.com/?gr=b10&ugr=struct|website=w3sDesign.com|access-date=2017-08-12}}</ref>]] |
||
In the above [[Unified Modeling Language|UML]] [[class diagram]], the <code>AbstractClass</code> defines a <code>templateMethod()</code> operation that defines the skeleton (template) of a behavior by |
In the above [[Unified Modeling Language|UML]] [[class diagram]], the <code>AbstractClass</code> defines a <code>templateMethod()</code> operation that defines the skeleton (template) of a behavior by |
||
* implementing the invariant parts of the behavior and |
* implementing the invariant parts of the behavior and |
||
* sending to '''self''' the messages <code>primitive1()</code> and <code>primitive2()</code> , which, because they are implemented in <code>SubClass1</code> , allow that subclass to provide a variant implementation of those parts of the algorithm. |
* sending to '''self''' the messages <code>primitive1()</code> and <code>primitive2()</code> , which, because they are implemented in <code>SubClass1</code> , allow that subclass to provide a variant implementation of those parts of the algorithm. |
||
[[Image:Template Method pattern in LePUS3.gif|thumb|none|300px|Template Method in [[Lepus3|LePUS3]].<ref>LePUS3 legend. Retrieved from http://lepus.org.uk/ref/legend/legend.xml.</ref>]] |
[[Image:Template Method pattern in LePUS3.gif|thumb|none|300px|Template Method in [[Lepus3|LePUS3]].<ref>LePUS3 legend. Retrieved from http://lepus.org.uk/ref/legend/legend.xml.</ref>]] |
||
Line 34: | Line 32: | ||
==Usage== |
==Usage== |
||
The template method is used in frameworks, where each implements the invariant parts of a domain's architecture, while providing hook methods for customization. This is an example of [[inversion of control]]. The template method is used for the following reasons.<ref name=":1">{{cite web | url = http://sourcemaking.com/design_patterns/template_method | title = Template Method Design Pattern | publisher = Source Making - teaching IT professional | quote = Template Method is used prominently in frameworks. | |
The ''template method'' is used in frameworks, where each implements the invariant parts of a domain's architecture, while providing hook methods for customization. This is an example of [[inversion of control]]. The template method is used for the following reasons.<ref name=":1">{{cite web | url = http://sourcemaking.com/design_patterns/template_method | title = Template Method Design Pattern | publisher = Source Making - teaching IT professional | quote = Template Method is used prominently in frameworks. | access-date = 2012-09-12}}</ref> |
||
* It lets subclasses implement varying behavior (through [[Method overriding (programming)|overriding]] of the hook methods).<ref name=":3">{{Cite book|title=Pro Objective-C Design Patterns for iOS|last=Chung|first=Carlo|publisher=Apress|year=2011|isbn=978-1-4302-3331-2|location=Berkeley, CA|pages=266 |
* It lets subclasses implement varying behavior (through [[Method overriding (programming)|overriding]] of the hook methods).<ref name=":3">{{Cite book|title=Pro Objective-C Design Patterns for iOS|last=Chung|first=Carlo|publisher=Apress|year=2011|isbn=978-1-4302-3331-2|location=Berkeley, CA|pages=266}}</ref> |
||
* It avoids duplication in the code: the general workflow of the algorithm is implemented once in the abstract class's template method, and necessary variations are implemented in the subclasses.<ref name=":3" /> |
* It avoids duplication in the code: the general workflow of the algorithm is implemented once in the abstract class's template method, and necessary variations are implemented in the subclasses.<ref name=":3" /> |
||
* It controls the point(s) at which specialization is permitted. If the subclasses were to simply override the template method, they could make radical and arbitrary changes to the workflow. In contrast, by overriding only the hook methods, only certain specific details of the workflow can be changed,<ref name=":3" /> and the overall workflow is left intact. |
* It controls the point(s) at which specialization is permitted. If the subclasses were to simply override the template method, they could make radical and arbitrary changes to the workflow. In contrast, by overriding only the hook methods, only certain specific details of the workflow can be changed,<ref name=":3" /> and the overall workflow is left intact. |
||
=== Use with code generators === |
=== Use with code generators === |
||
The template pattern is useful when working with auto-generated code. The challenge of working with generated code is that changes to the source code will lead to changes in the generated code; if hand-written modifications have been made to the generated code, these will be lost. How, then, should the generated code be customized? |
The template pattern is useful when working with auto-generated code. The challenge of working with generated code is that changes to the source code will lead to changes in the generated code; if hand-written modifications have been made to the generated code, these will be lost. How, then, should the generated code be customized? |
||
The Template pattern provides a solution. If the generated code follows the template method pattern, the generated code will all be an abstract superclass. Provided that hand-written customizations are confined to a subclass, the code generator can be run again without risk of over-writing these modifications. When used with code generation, this pattern is sometimes referred to as the [[Generation gap (pattern)|generation gap pattern]].<ref>{{cite book|last1=Vlissides|first1=John|title=Pattern Hatching: Design Patterns Applied|date=1998-06-22|publisher=Addison-Wesley Professional|isbn=978-0201432930|pages=85–101|url=http://www.informit.com/store/pattern-hatching-design-patterns-applied-9780201432930}}</ref> |
The Template pattern provides a solution. If the generated code follows the template method pattern, the generated code will all be an abstract superclass. Provided that hand-written customizations are confined to a subclass, the code generator can be run again without risk of over-writing these modifications. When used with code generation, this pattern is sometimes referred to as the [[Generation gap (pattern)|generation gap pattern]].<ref>{{cite book|last1=Vlissides|first1=John|title=Pattern Hatching: Design Patterns Applied|date=1998-06-22|publisher=Addison-Wesley Professional|isbn=978-0201432930|pages=85–101|url=http://www.informit.com/store/pattern-hatching-design-patterns-applied-9780201432930}}</ref> |
||
== |
==C++ example== |
||
This C++14 implementation is based on the pre C++98 implementation in the book. |
|||
<syntaxhighlight lang="php"> |
|||
abstract class Game |
|||
{ |
|||
abstract protected function initialize(); |
|||
abstract protected function startPlay(); |
|||
abstract protected function endPlay(); |
|||
[[File:Cpp template method pattern UML.svg|Cpp template method pattern UML.svg]] |
|||
/** Template method */ |
|||
public final function play() |
|||
{ |
|||
/** Primitive */ |
|||
$this->initialize(); |
|||
<syntaxhighlight lang="c++"> |
|||
/** Primitive */ |
|||
#include <iostream> |
|||
$this->startPlay(); |
|||
#include <memory> |
|||
class View { // AbstractClass |
|||
/** Primitive */ |
|||
public: |
|||
$this->endPlay(); |
|||
// defines abstract primitive operations that concrete subclasses define to implement steps of an algorithm. |
|||
} |
|||
virtual void doDisplay() {} |
|||
} |
|||
// implements a template method defining the skeleton of an algorithm. The template method calls primitive operations as well as operations defined in AbstractClass or those of other objects. |
|||
void display() { |
|||
class Mario extends Game |
|||
setFocus(); |
|||
{ |
|||
doDisplay(); |
|||
protected function initialize() |
|||
resetFocus(); |
|||
} |
|||
echo "Mario Game Initialized! Start playing.", PHP_EOL; |
|||
virtual ~View() = default; |
|||
} |
|||
private: |
|||
void setFocus() { |
|||
protected function startPlay() |
|||
std::cout << "View::setFocus\n"; |
|||
{ |
|||
} |
|||
echo "Mario Game Started. Enjoy the game!", PHP_EOL; |
|||
void resetFocus() { |
|||
} |
|||
std::cout << "View::resetFocus\n"; |
|||
} |
|||
}; |
|||
class MyView : public View { // ConcreteClass |
|||
protected function endPlay() |
|||
// implements the primitive operations to carry out subclass-specific steps of the algorithm. |
|||
{ |
|||
void doDisplay() override { |
|||
echo "Mario Game Finished!", PHP_EOL; |
|||
// render the view's contents |
|||
} |
|||
std::cout << "MyView::doDisplay\n"; |
|||
} |
|||
}; |
|||
int main() { |
|||
// The smart pointers prevent memory leaks |
|||
std::unique_ptr<View> myview = std::make_unique<MyView>(); |
|||
myview->display(); |
|||
} |
} |
||
</syntaxhighlight> |
|||
The program output is |
|||
class Tankfight extends Game |
|||
{ |
|||
protected function initialize() |
|||
{ |
|||
echo "Tankfight Game Initialized! Start playing.", PHP_EOL; |
|||
} |
|||
<syntaxhighlight lang="c++"> |
|||
protected function startPlay() |
|||
View::setFocus |
|||
{ |
|||
MyView::doDisplay |
|||
echo "Tankfight Game Started. Enjoy the game!", PHP_EOL; |
|||
View::resetFocus |
|||
} |
|||
protected function endPlay() |
|||
{ |
|||
echo "Tankfight Game Finished!", PHP_EOL; |
|||
} |
|||
} |
|||
$game = new Tankfight(); |
|||
$game->play(); |
|||
$game = new Mario(); |
|||
$game->play(); |
|||
</syntaxhighlight> |
</syntaxhighlight> |
||
== See also == |
== See also == |
||
* [[Inheritance ( |
* [[Inheritance (object-oriented programming)]] |
||
* [[Method overriding (programming)]] |
* [[Method overriding (programming)]] |
||
* [[GRASP (object-oriented design)|GRASP (object-oriented designer)]] |
* [[GRASP (object-oriented design)|GRASP (object-oriented designer)]] |
||
Line 122: | Line 105: | ||
== External links == |
== External links == |
||
{{ |
{{Wikibooks|Computer Science Design Patterns|Template method}} |
||
* [https://www.codeproject.com/Articles/307452/common-use-of-Template-Design-pattern-Design-pat Six common uses of the template pattern] |
* [https://www.codeproject.com/Articles/307452/common-use-of-Template-Design-pattern-Design-pat Six common uses of the template pattern] |
||
* [http://www.devshed.com/c/a/PHP/Working-with-Template-Classes-in-PHP-5/ Working with Template Classes in PHP 5] |
|||
* [http://sourcemaking.com/design_patterns/template_method Template Method Design Pattern] |
* [http://sourcemaking.com/design_patterns/template_method Template Method Design Pattern] |
||
{{Design Patterns patterns}} |
|||
[[Category:Software design patterns]] |
[[Category:Software design patterns]] |
Revision as of 12:20, 9 April 2024
This article includes a list of general references, but it lacks sufficient corresponding inline citations. (March 2012) |
In object-oriented programming, the template method is one of the behavioral design patterns identified by Gamma et al.[1] in the book Design Patterns. The template method is a method in a superclass, usually an abstract superclass, and defines the skeleton of an operation in terms of a number of high-level steps. These steps are themselves implemented by additional helper methods in the same class as the template method.
The helper methods may be either abstract methods, in which case subclasses are required to provide concrete implementations, or hook methods, which have empty bodies in the superclass. Subclasses can (but are not required to) customize the operation by overriding the hook methods. The intent of the template method is to define the overall structure of the operation, while allowing subclasses to refine, or redefine, certain steps.[2]
Overview
This pattern has two main parts:
- The "template method" is implemented as a method in a base class (usually an abstract class). This method contains code for the parts of the overall algorithm that are invariant. The template ensures that the overarching algorithm is always followed.[1] In the template method, portions of the algorithm that may vary are implemented by sending self messages that request the execution of additional helper methods. In the base class, these helper methods are given a default implementation, or none at all (that is, they may be abstract methods).
- Subclasses of the base class "fill in" the empty or "variant" parts of the "template" with specific algorithms that vary from one subclass to another.[3] It is important that subclasses do not override the template method itself.
At run-time, the algorithm represented by the template method is executed by sending the template message to an instance of one of the concrete subclasses. Through inheritance, the template method in the base class starts to execute. When the template method sends a message to self requesting one of the helper methods, the message will be received by the concrete sub-instance. If the helper method has been overridden, the overriding implementation in the sub-instance will execute; if it has not been overridden, the inherited implementation in the base class will execute. This mechanism ensures that the overall algorithm follows the same steps every time while allowing the details of some steps to depend on which instance received the original request to execute the algorithm.
This pattern is an example of inversion of control because the high-level code no longer determines what algorithms to run; a lower-level algorithm is instead selected at run-time.
Some of the self-messages sent by the template method may be to hook methods. These methods are implemented in the same base class as the template method, but with empty bodies (i.e., they do nothing). Hook methods exist so that subclasses can override them, and can thus fine-tune the action of the algorithm without the need to override the template method itself. In other words, they provide a "hook" on which to "hang" variant implementations.
Structure
UML class diagram
In the above UML class diagram, the AbstractClass
defines a templateMethod()
operation that defines the skeleton (template) of a behavior by
- implementing the invariant parts of the behavior and
- sending to self the messages
primitive1()
andprimitive2()
, which, because they are implemented inSubClass1
, allow that subclass to provide a variant implementation of those parts of the algorithm.
Usage
The template method is used in frameworks, where each implements the invariant parts of a domain's architecture, while providing hook methods for customization. This is an example of inversion of control. The template method is used for the following reasons.[3]
- It lets subclasses implement varying behavior (through overriding of the hook methods).[6]
- It avoids duplication in the code: the general workflow of the algorithm is implemented once in the abstract class's template method, and necessary variations are implemented in the subclasses.[6]
- It controls the point(s) at which specialization is permitted. If the subclasses were to simply override the template method, they could make radical and arbitrary changes to the workflow. In contrast, by overriding only the hook methods, only certain specific details of the workflow can be changed,[6] and the overall workflow is left intact.
Use with code generators
The template pattern is useful when working with auto-generated code. The challenge of working with generated code is that changes to the source code will lead to changes in the generated code; if hand-written modifications have been made to the generated code, these will be lost. How, then, should the generated code be customized?
The Template pattern provides a solution. If the generated code follows the template method pattern, the generated code will all be an abstract superclass. Provided that hand-written customizations are confined to a subclass, the code generator can be run again without risk of over-writing these modifications. When used with code generation, this pattern is sometimes referred to as the generation gap pattern.[7]
C++ example
This C++14 implementation is based on the pre C++98 implementation in the book.
#include <iostream>
#include <memory>
class View { // AbstractClass
public:
// defines abstract primitive operations that concrete subclasses define to implement steps of an algorithm.
virtual void doDisplay() {}
// implements a template method defining the skeleton of an algorithm. The template method calls primitive operations as well as operations defined in AbstractClass or those of other objects.
void display() {
setFocus();
doDisplay();
resetFocus();
}
virtual ~View() = default;
private:
void setFocus() {
std::cout << "View::setFocus\n";
}
void resetFocus() {
std::cout << "View::resetFocus\n";
}
};
class MyView : public View { // ConcreteClass
// implements the primitive operations to carry out subclass-specific steps of the algorithm.
void doDisplay() override {
// render the view's contents
std::cout << "MyView::doDisplay\n";
}
};
int main() {
// The smart pointers prevent memory leaks
std::unique_ptr<View> myview = std::make_unique<MyView>();
myview->display();
}
The program output is
View::setFocus
MyView::doDisplay
View::resetFocus
See also
- Inheritance (object-oriented programming)
- Method overriding (programming)
- GRASP (object-oriented designer)
- Adapter pattern
- Strategy pattern
References
- ^ a b Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John (1994). "Template Method". Design Patterns. Addison-Wesley. pp. 325–330. ISBN 0-201-63361-2.
- ^ Freeman, Eric; Freeman, Elisabeth; Sierra, Kathy; Bates, Bert (2004). Hendrickson, Mike; Loukides, Mike (eds.). Head First Design Patterns (paperback). Vol. 1. O'REILLY. pp. 289, 311. ISBN 978-0-596-00712-6. Retrieved 2012-09-12.
- ^ a b "Template Method Design Pattern". Source Making - teaching IT professional. Retrieved 2012-09-12.
Template Method is used prominently in frameworks.
- ^ "The Template Method design pattern - Structure". w3sDesign.com. Retrieved 2017-08-12.
- ^ LePUS3 legend. Retrieved from http://lepus.org.uk/ref/legend/legend.xml.
- ^ a b c Chung, Carlo (2011). Pro Objective-C Design Patterns for iOS. Berkeley, CA: Apress. p. 266. ISBN 978-1-4302-3331-2.
- ^ Vlissides, John (1998-06-22). Pattern Hatching: Design Patterns Applied. Addison-Wesley Professional. pp. 85–101. ISBN 978-0201432930.