Imagine a workday morning. You get up, go through the regular routine, but put on nice clothes today
because you have a presentation to give. Next morning, you wake up, do the regular routine, put on presentable clothes,
but not as spiffy as yesterday. Oh, and you hit a bakery on the way to work because you wanted to celebrate
someone's achievement. On your day off, you wake up, brush teeth, put on sports outfit and go for a run.
The Template Method pattern is about a routine that is happening every time, but allowing for slight
variations. In this case, an abstract class
Morning
would have a getReady()
method, with the following items:
shutOffAlarm()
brushTeeth()
shower()
getDressed()
eatBreakfast()
headToThePlaceOfMorningActivity()
purchaseSomethingOnTheWay()
MondayMorning
, method getDressed
can have specific outfit for a day busy with mornings. And for a class
SaturdayMorning
, the method shutOffAlarm
could do nothing since you have no alarm on weekends. Each subclass of
Morning
still goes throud the getReady
method, just with its own variations.
The code example looks at the way an e-mail is composed. One e-mail is sent to the CEO of a company, it has many parts making it
an official document easy to read and with lots of details. Another e-mail is a quick note to a friend. Both classes inherit from an abstract
class
Email
, and both go through the compose
method's routine, but the e-mail to a friend skips a bunch of formalities
and goes straight to the details.
abstract class Email {
compose(): void {
this.salutation();
this.summary();
this.discussion();
this.figures();
this.closingStatements();
this.signature();
this.contactInfo();
}
protected abstract salutation(): void; //needs to be overwritten in child class
protected summary(): void {}
protected abstract discussion(): void; //needs to be overwritten in child class
protected figures(): void {}
protected closingStatements(): void {}
protected signature(): void {}
protected contactInfo(): void {}
}
class EmailToCEO extends Email {
salutation(): void {
console.log("Dear Mr. CEO");
}
summary(): void {
console.log("Everything is great");
}
discussion(): void {
console.log(
"Since you have been our CEO and making such great decisions, our profits increased."
);
}
figures(): void {
console.log(
"Here are three tables that show how much more money we are making."
);
}
closingStatements(): void {
console.log("In summary, all is well");
}
signature(): void {
console.log("Sincerely yours, your best worker.");
}
contactInfo(): void {
console.log("You can contact me at 555-5555");
}
}
class EmailToFriend extends Email {
salutation(): void {
console.log("yo!");
}
discussion(): void {
console.log("let's have a party!");
}
contactInfo(): void {
console.log;
}
}
Test code:
console.log("Email to CEO:");
let c = new EmailToCEO();
c.compose();
console.log("\nEmail to a friend:");
let f = new EmailToFriend();
f.compose();
Result:
Email to CEO:
Dear Mr. CEO
Everything is great
Since you have been our CEO and making such great decisions, our profits increased.
Here are three tables that show how much more money we are making.
In summary, all is well
Sincerely yours, your best worker.
You can contact me at 555-5555
Email to a friend:
yo!
let's have a party!
Use this patterns when the steps among several processes are common and it is easy to separate those steps and override
implementation for each individual case.