The template method

The template method pattern is a simple pattern used when you need a general behavior but where the details of the algorithm must be specific to subclasses.

Role

The template method pattern isolates various parts of an algorithm. The algorithm skeleton is defined in an abstract class where some steps of the algorithm are delegated to its subclasses and some others are fixed in the abstract class itself and cannot be overridden in subclasses.

Design

The following diagram describes the generic structure of the template method:

Design

Participants

The participants of this pattern are as follows:

  • The AbstractClass, which defines the template method, and the signature of the sub parts of the algorithm are invoked by the template method.
  • The ConcreteClass implements abstract methods used by the template method of the AbstractClass. It is possible to have several concrete classes.

Collaboration

The algorithm defined in the template method is called TemplateMethod() in the generic UML class diagram and invokes parts of the algorithm in the subclasses.

Illustration

You are working on a new simulation game with several personage types. Each personage has several properties, such as money, happiness, fatigue, hungry, and knowledge.

Each of these personages can "Play" a day. A day is decomposed in several parts:

  • GetUp
  • EatBreakFast
  • DoWashingUp
  • GoToWork
  • Work
  • GoHome
  • DoPersonalActivites
  • EatDinner
  • Sleep

We have three types of personages: Student, Searcher, and FireMan; each of them can "play" a day but doesn't react in the same way depending on the day phase.

So, we will override parts of the algorithm in the concrete class by defining the personage type. The only part of the algorithm that is fixed is the DoWashingUp function. This part will not and cannot be overridden in subclasses.

Implementation

Open the TemplateMethod project with Xcode. The project is quite simple. We will find the TemplateMethod folder in the AbstractPersonage.Swift class and all concrete subclasses that implement parts of the algorithm in the three concrete classes: Searcher, Student, and FireMan:

Implementation

To implement the preceding example, we will first prepare our abstract class that defines a personage. Remember to consider this class as an abstract class. You must not instantiate it directly to your code, but you must instantiate only a subclass of AbstractPersonage:

class AbstractPersonage {
  private final var fatigue = 100
  private final var money = 0
  private final var happiness = 100
  private final var hungry = 100
  private final var knowledge = 100
  private final var name:String!
  
  final var canBePaid: Bool = true
  
  required init(name: String) {
   self.name = name
  }
  
  
  func toString() {
    print("("Name: (name) / fatigue : (Fatigue) / happiness (Happiness) / Hungry (Hungry) / knowledge (Fatigue) / money: (Money) / ")
  }
  
  //Play a day for the Personage
  func playDay() {
    print("PLAYING DAY")
    print("Get Up!")
    getUp()
    print("Eat Breakfast")
    eatBreakfast()
    doWashingUp()
    print("Go to work")
    goToWork()
    print("Work")
    work()
    
    if canBePaid {
      print("Receive Pay")
      getPaid()
    }
    print("BackHome")
    backToHome()
    
    print("Do personal activities")
    doPersonalActivities()
    
    print("Eat dinner")
    eatDinner()
    
    print("Sleep")
    sleep()
  }
  
  
  func getUp() {
    Fatigue = 0
    Happiness = 25
    Hungry = -25
    Knowledge = 0
  }
  
  func eatBreakfast() {
    Fatigue = -5
    Happiness = 25
    Hungry = 60
    Knowledge = 0
  }
  final func doWashingUp() {
    print("do washing up")
  }
  
  func goToWork() {
    Fatigue = -15
    Happiness = -15
    Hungry = -10
    Knowledge = 0
  }
  func work(){
    Fatigue = -40
    Happiness = -25
    Hungry = -40
    Knowledge = 25
  }
  
  func getPaid() {
    Money = 1000
  }
  
  func backHome() {
    Fatigue = -15
    Happiness = 10
    Hungry = -10
    Knowledge = 0
  }
  
  func doPersonalActivities() {
    Fatigue = -15
    Happiness = 15
    Hungry = -10
    Knowledge = 0
  }
  
  func eatDinner() {
    Fatigue = -10
    Happiness = 5
    Hungry = 40
    Knowledge = 0
  }
  func sleep() {
    Fatigue = 90
    Happiness = 0
    Hungry = -5
    Knowledge = 2
  }
  
  var Fatigue: Int {
    get{
      return fatigue
    }
    set{
    fatigue += newValue
    }
  }
  
  var Hungry: Int {
    get{
      return hungry
    }
    set{
      hungry += newValue
    }
  }
  
  var Happiness: Int {
    get{
      return happiness
    }
    set{
      happiness += newValue
    }
  }
  
  var Money: Int {
    get{
      return money
    }
    set{
      money += newValue
    }
  }
  
  var Knowledge: Int {
    get{
      return knowledge
    }
    set{
      knowledge += newValue
    }
  }
}

In the preceding code, we can distinguish three parts. The first part is a private variable declaration. We mark the access modifier to avoid modification in subclasses:

  private final var fatigue = 100
  private final var money = 0
  …

Our playDay template method invokes all the parts of the algorithm:

//Play a day for the Personage
  func playDay() {
    print("PLAYING DAY")
    print("Get Up!")
    getUp()
    print("Eat Breakfast")
    eatBreakfast()
    doWashingUp()
    print("Go to work")
    goToWork()
    print("Work")
    work()
    
    if canBePaid {
      print("Receive Pay")
      getPaid()
    }
    print("BackHome")
    backHome()
    
    print("Do personal activities")
    doPersonalActivities()
    
    print("Eat dinner")
    eatDinner()

   doWashingUp()
    
    print("Sleep")
    sleep()
  }

… 

Then, we define the method signatures that are parts of the algorithm and we will eventually implement them. Here, we define a default implementation of each method:

func eatBreakfast() {
    Fatigue = -5
    Happiness = 25
    Hungry = 60
    Knowledge = 0
  }
  
  func goToWork() {
    Fatigue = -15
    Happiness = -15
    Hungry = -10
    Knowledge = 0
  }

//others methods 

Finally, we define our computed properties to modify the setter behavior by making an addition to itself when a new value is assigned to the property:

  var Fatigue: Int {
    get{
      return fatigue
    }
    set{
    fatigue += newValue
    }
  }
  
  var Hungry: Int {
    get{
      return hungry
    }
    set{
      hungry += newValue
    }
  }

The following two steps make our sample better:

  • We add a required constructor where we inject a name to the personage that we will instantiate:
      required init(name: String) {
      self.name = name
      }
  • We define a toString() method that will print all the properties and values of the personage:
      func toString() {
        print("Name: (name) / fatigue : (Fatigue) / happiness (Happiness) / Hungry (Hungry) / knowledge (Fatigue) / money: (Money) / ")
      }

Well, our abstract class that implements the template method is complete. Now, we have a skeleton to make a new concrete personage, for example, a student.

The student doesn't have a job, so he won't get paid. The student reads books during his personal activities.

So, we will create a new Student class that implements our abstract class that contains the template method, and we will override only parts of the algorithm that changes in the parent class:

class Student: AbstractPersonage {
  
  required init(name: String) {
    super.init(name: name)
    //student cannot be paid
    canBePaid = false
  }
  
  override func doPersonalActivities() {
    //student Read Books during its personal activities
    //so life indicators must be updated
    Fatigue = -5
    Happiness = 15
    Hungry = -5
    Knowledge = 15
  }
}

In the same way, we define the Searcher and FireMan classes that implement our abstract classes and both can be paid but not the same amount. Also, each of them must override some parts of the algorithm to be more accurate with specificity of the entity that the class represent:

For the Searcher class, we will implement the AbstractPersonage protocol as follows:

class Searcher: AbstractPersonage {
  
  override func getPaid() {
    Money = 3000/30
  }
  
  override func sleep() {
    //Searcher sleep very well
    Fatigue = 90
    Happiness = 0
    Hungry = -5
    Knowledge = 10
  }
  
  override func doPersonalActivitie() {
    //Searcher Read ScientificBooks during its personal activities
    //so life indicators must be updated
    Fatigue = -5
    Happiness = 10
    Hungry = -5
    Knowledge = 25
  }
}

For the FireMan class, we will implement it as follows:

import Foundation

class FireMan: AbstractPersonage {
  
  override func getPaid() {
    Money = 2500/30
  }
  
  override func sleep() {
    //FireMan doesn't sleep a lot
    Fatigue = 80
    Happiness = 5
    Hungry = -5
    Knowledge = 0
  }
  
  override func doPersonalActivities() {
    //FireMan makes lot of sports during personal activities
    //so life indicators must be updated
    Fatigue = -10
    Happiness = 5
    Hungry = -5
    Knowledge = 15
  }
  
  override func work() {
    Fatigue = -25
    Happiness = -55
    Hungry = -45
    Knowledge = 10
  }
  
  
}

Our template method and concrete classes are now ready. We can now write in the main.swift file. Our simple client will instantiate a student called Simon, a searcher called Natasha, and a fireman called Edward.

We will display the properties of each of them before simulating 30 days of their life. Then, we will tell these three personages to live for 30 days using the following code:

student.toString()
searcher.toString()
fireMan.toString()

Then, we will play 30 days of life in a for loop:

for i in 1...30{
  student.playDay()
  searcher.playDay()
  fireMan.playDay()
}

At the end of these 30 days of life, we will check the properties of each of them:

print("- **** 30 days later:")
student.toString()
searcher.toString()
fireMan.toString()

The final code is as follows:

  import Foundation

let student = Student(name: "Simon")
let searcher = Searcher(name: "Natasha")
let fireMan = FireMan(name:"Edward")

print("- **** Starting with:")
student.toString()
searcher.toString()
fireMan.toString()

//Play a month
for i in 1...30{
  print("**************")
  print("Play Day (i) ")
  print("**************")
  student.playDay()
  searcher.playDay()
  fireMan.playDay()
}
print("- **** 30 days later:")
student.toString()
searcher.toString()
fireMan.toString()

Click on the Run button. On the console, you will see the results after 30 days of life:

Implementation
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset