Behavioral Design Pattern
Kotlin Design Patterns: Template Method Explained

Purpose of the pattern
Overriding only a specific algorithm step without changing its general structure. You have a general algorithm structure in the superclass, but make one of the abstract steps so that the subclasses must implement it.
It’s used to either create variants of the class or to reuse base class logic in multiple subclasses.
What do we get from that?
- Avoidance of code duplication.
- Replaceable parts of the program.
- You’re able to add new subclasses without modification of existing subclasses.
However, this pattern can be a trap! It’s tough to maintain. If you need to extend the superclass, you’ll likely have to change all subclasses. Unfortunately, it must use inheritance, and the superclass might limit some of the subclasses.
Implementation

Here Template
is an abstract class
that has a public templateMethod
and abstract doPartOfSomething
that is used inside templateMethod
. This way, we force all classes that inherit from Template
to implement that method. Here Template1
and Template2
can have different structures.
Sometimes the doPartOfSomething
method can have a default implementation. Then, the subclasses will make different variants instead of implementing them from scratch.
It’s also common to add more than a single abstract method to the Template
. If you want the Template to behave like a base class, use Interface delegation instead of abstract class to prevent most of the disadvantages of this pattern.
Example
Your Task is to create a Character System. You’ll have to create Warrior
and Mage
, likely, you’ll also have to add more characters. It’s a turn-based game and each Character will attack differently. It’s a good use case for a TemplateMethod because all of them are based on something in general.

Let’s start by creating our abstract class Character
as others depend on it:
abstract class Character {
fun completeTurn() {
println("Finishing a turn with ${attack()} attack")
}
protected abstract fun attack(): String
}
Now, for the concrete classes:
class Mage : Character() {
override fun attack() = "Fireball"
}
class Warrior: Character() {
override fun attack() = "Sword"
}
Now for the usage:
fun main() {
val warrior = Warrior() // Finishing a turn with Sword attack
warrior.completeTurn()
val mage = Mage() // Finishing a turn with Fireball attack
mage.completeTurn()
warrior.attack() // Compilation error attack is protected
}
If Mage
or Warrior
need to be extended by additional functions, they can do so without modifying the existing codebase, which is important to keep in mind when coding.
You might also want to make attack
public instead of hiding it under completeTurn
.
In general, I think I would discourage you from using this pattern if possible.
Thanks for reading! Please clap if you learned something, and follow me for more!
Learn more about design patterns:



Based on the book:
“Wzorce projektowe : elementy oprogramowania obiektowego wielokrotnego użytku” — Erich Gamma Autor; Janusz Jabłonowski (Translator); Grady Booch (Introduction author); Richard Helm (Author); Ralph Johnson (Author); John M Vlissides (Author)