Template Method Design Pattern
Video Lecture
Overview
... To read hidden text, either pause Video Lectures, refer to Book or subscribe to Medium Membership.
Terminology
... To read hidden text, either pause Video Lectures, refer to Book or subscribe to Medium Membership.
Template Method UML Diagram

Source Code
... To read hidden text, either pause Video Lectures, refer to Book or subscribe to Medium Membership.
./src/template/template-method-concept.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 | // The Template Method Pattern Concept"
abstract class AbstractClass {
// A template class containing a template method and primitive methods
stepOne(): void {
// Hooks are normally empty in the abstract class. The
// implementing class can optionally override providing a custom
// implementation
}
abstract stepTwo(): void
// An abstract method that must be overridden in the implementing
// class. It has been given `@abstractmethod` decorator so that
// pylint shows the error
stepThree(): void {
// Hooks can also contain default behavior and can be optionally
// overridden
console.log(
'Step Three is a hook that prints this line by default.'
)
}
templateMethod() {
// This is the template method that the subclass will call.
// The subclass(implementing class) doesn't need to override this
// method since it has would have already optionally overridden
// the following methods with its own implementations
this.stepOne()
this.stepTwo()
this.stepThree()
}
}
class ConcreteClassA extends AbstractClass {
// A concrete class that only overrides step two"
stepTwo() {
console.log('Class_A : Step Two (overridden)')
}
}
class ConcreteClassB extends AbstractClass {
// A concrete class that only overrides steps one, two and three"
stepOne() {
console.log('Class_B : Step One (overridden)')
}
stepTwo() {
console.log('Class_B : Step Two. (overridden)')
}
stepThree() {
console.log('Class_B : Step Three. (overridden)')
}
}
// The Client
const CLASS_A = new ConcreteClassA()
CLASS_A.templateMethod()
const CLASS_B = new ConcreteClassB()
CLASS_B.templateMethod()
|
Output
node ./dist/template-method/template-method-concept.js
Class_A : Step Two (overridden)
Step Three is a hook that prints this line by default.
Class_B : Step One (overridden)
Class_B : Step Two. (overridden)
Class_B : Step Three. (overridden)
Template Method Use Case
... To read hidden text, either pause Video Lectures, refer to Book or subscribe to Medium Membership.
Template Method Use Case UML Diagram

Source Code
./src/template/client.ts
| // The Template Pattern Use Case Example
import TextDocument from './text-document'
import HTMLDocument from './html-document'
const TEXT_DOCUMENT = new TextDocument()
TEXT_DOCUMENT.createDocument('Some Text')
const HTML_DOCUMENT = new HTMLDocument()
HTML_DOCUMENT.createDocument('Line 1\nLine 2')
|
./src/template/abstract-document.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 | // An abstract document containing a combination of hooks and abstract methods
export interface Document {
[id: string]: string
}
export abstract class AbstractDocument {
// A template class containing a template method and primitive methods
document: Document = {}
abstract title(document: Document): void
// Must implement
description?(document: Document): void
// Optional
author?(document: Document): void
// Optional
backgroundColour(document: Document): void {
// Optional with a default behavior
document['bg-col'] = 'white'
}
abstract text(document: Document, text: string): void
// Must implement
footer?(document: Document): void
// Optional
print(document: Document): void {
// Optional with a default behavior"
console.log('----------------------')
Object.keys(document).forEach((attribute: string) => {
console.log(`${attribute}\t: ${document[attribute]}`)
})
console.log()
}
createDocument(text: string): void {
// The template method
this.title(this.document)
if (this.description) this.description(this.document)
if (this.author) this.author(this.document)
this.backgroundColour(this.document)
this.text(this.document, text)
if (this.footer) this.footer(this.document)
this.print(this.document)
}
}
|
./src/template/text-document.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | import { Document, AbstractDocument } from './abstract-document'
export default class TextDocument extends AbstractDocument {
title(document: Document): void {
document['title'] = 'New Text Document'
}
text(document: Document, text: string): void {
document['text'] = text
}
footer(document: Document): void {
document['footer'] = '-- Page 1 --'
}
}
|
./src/template/html-document.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 | // A HTML document concrete class of AbstractDocument
import { Document, AbstractDocument } from './abstract-document'
export default class HTMLDocument extends AbstractDocument {
title(document: Document): void {
document['title'] = 'New HTML Document'
}
text(document: Document, text: string): void {
// Putting multiple lines into there own p tags
const lines = text.split('\n')
let markup = ''
lines.forEach((line) => {
markup = markup + ' <p>' + line + '</p>\n'
document['text'] = markup.substring(0, markup.length - 1)
})
}
print(document: Document): void {
// overriding print to output with html tags
console.log('<html>')
console.log(' <head>')
Object.keys(document).forEach((attribute: string) => {
if (
['title', 'description', 'author'].indexOf(attribute) > -1
) {
console.log(
` <${attribute}>${document[attribute]}</${attribute}>`
)
}
if (attribute === 'bg-col') {
console.log(' <style>')
console.log(' body {')
console.log(
` background-color: ${document[attribute]};`
)
console.log(' }')
console.log(' </style>')
}
})
console.log(' </head>')
console.log(' <body>')
console.log(`${document['text']}`)
console.log(' </body>')
console.log('</html>')
}
}
|
Output
node ./dist/template-method/client.js
----------------------
title : New Text Document
bg-col : white
text : Some Text
footer : -- Page 1 --
<html>
<head>
<title>New HTML Document</title>
<style>
body {
background-color: white;
}
</style>
</head>
<body>
<p>Line 1</p>
<p>Line 2</p>
</body>
</html>
Summary
... To read hidden text, either pause Video Lectures, refer to Book or subscribe to Medium Membership.