Implementation

Let’s say, in the Flutter application we want to create an algorithm which calculates the BMI (body mass index) of students. The algorithm retrieves students’ data, applies students filtering (if necessary), calculates their BMI and provides the results. Also, we want to retrieve students information from different data sources and we want to have a separate algorithm which includes only teenage students for the calculations. As you can see, the structure of the algorithm is general, but the implementation details (algorithm steps) vary among different implementations. To implement this algorithm, we would use the Template method design pattern.

Class diagram

The class diagram below shows the implementation of the Template Method design pattern.

Class Diagram — Implementation of the Template Method design pattern

The main class in the diagram is StudentsBmiCalculator. Its primary purpose is to define a template of the BMI calculation algorithm which returns a list of Student objects (with the calculated BMI for each student) as a result via calculateBmiAndReturnStudentList() method. This abstract class is used as a template (base class) for the concrete implementations of the students’ BMI calculation algorithm — StudentsXmlBmiCalculator, StudentsJsonBmiCalculator and TeenageStudentsJsonBmiCalculator. StudentsXmlBmiCalculator uses the XmlStudentsApi to retrieve students information as an XML string and returns it as a list of Student objects via the overridden getStudentsData() method. Both of the other two implementations (StudentsJsonBmiCalculator and TeenageStudentsJsonBmiCalculator) uses the JsonStudentsApi to retrieve students information in JSON format and returns the parsed data via the overridden getStudentsData() method. However, TeenageStudentsJsonBmiCalculator additionally reimplements (overrides) the doStudentsFiltering() hook method to filter out not teenage students before calculating the BMI values. StudentsSection UI widget uses the StudentsBmiCalculator abstraction to retrieve and represent the calculated results in TemplateMethodExample widget.

Note: it would make more sense to extract the XML or JSON parsing logic from the getStudentsData() method in the concrete calculation classes to a separate class using the Adapter design pattern, but for the demonstration purposes of the Template Method pattern and to show that the implementation of getStudentsData() may differ among the derived classes of the StudentsXmlBmiCalculator, I have decided to leave logic as it is now.

StudentsBmiCalculator

An abstract (template) class for the BMI calculation algorithm.

The algorithm consists of several steps:

Retrieve students data — getStudentsData(); Do students filtering (if needed) — doStudentsFiltering(); Calculate the BMI for each student — _calculateStudentsBmi(); Return students data — return studentList.

The first step is mandatory and should be implemented in each concrete implementation of the students BMI calculator — that is, the method getStudentsData() is abstract and must be overridden in the derived class (primitive operation). Students filtering step is optional, yet it could be overridden in the derived class. For this reason, doStudentsFiltering() method has a default implementation which does not change the workflow of the algorithm by default (hook operation). Other steps are defined in the algorithm’s template itself, are common for all implementations and could not be changed (final operations).

StudentsXmlBmiCalculator

A concrete implementation of the BMI calculation algorithm which uses XmlStudentsApi to retrieve data and implements the getStudentsData() method.

StudentsJsonBmiCalculator

A concrete implementation of the BMI calculation algorithm which uses JsonStudentsApi to retrieve data and implements the getStudentsData() method.

TeenageStudentsJsonBmiCalculator

A concrete implementation of the BMI calculation algorithm which uses JsonStudentsApi to retrieve data and implements the getStudentsData() method.

Additionally, the doStudentsFiltering() hook method is overridden to filter out not teenage students.

Student

A simple class to store the student’s information.

JsonStudentsApi

A fake API which returns students’ information as JSON string.

XmlStudentsApi

A fake API which returns students’ information as an XML string.

Example

First of all, a markdown file is prepared and provided as a pattern’s description:

The example itself uses StudentsSection component which requires a specific BMI calculator of type StudentsBmiCalculator to be provided via a constructor. For this example, we inject three different implementations of BMI calculator (StudentsXmlBmiCalculator, StudentsJsonBmiCalculator and TeenageStudentsJsonBmiCalculator) which extend the same template (base class) — StudentsBmiCalculator — to three different StudentsSection widgets.

StudentsSection uses the injected BMI calculator of type StudentsBmiCalculator. The widget does not care about the specific implementation of the BMI calculator as long as it uses (extends) the same template (base class). This lets us provide different students’ BMI calculation algorithms/implementations without making any changes to the UI code.

The final result of the Template Method’s implementation looks like this:

All of the code changes for the Template Method design pattern and its example implementation could be found here.