Home Simplify Template Pattern (Behaviour Pattern)
Post
Cancel

Simplify Template Pattern (Behaviour Pattern)

Once Coder Orangu 🦧 was working on a problem.

πŸŒ‘ Outline

The Template pattern defines steps for an algorithm in a superclass and a subclass can override specific steps to provide desired behaviour without changing the execution flow of the algorithm. The function that decides the execution sequence of an algorithm is called the Template method.

Template - A structure to be followed for an algorithm.

πŸŒ₯️ Why Template

While writing code sometimes you might get into a situation where a standard set of steps to be performed to achieve the functionality. The easy option is to call these steps one by one at the required place. This way the desired functionality will be achieved however, the process is not standardised and not reusable.

For example, you are working on a news reader application. To display the news in the application a standard set of steps needs to be followed:

  1. Fetch the news from the source.
  2. parse the news feed.
  3. Categories the news (Entertainment, Top News etc.).
  4. Filter the duplicate news.
  5. Sort the categories & news based on timestamp.

Intially you have written a code that only supports XML. After 6 months of development, a new JSON-based feed source needs to be supported. From the above steps, the impact is only on the parsing step.

One basic approach will be at parsing time you will check if the response is XML then parse XML else parse JSON. This will work but this is not a scalable and easily maintained solution. If more response types need to be supported then more conditions and more change in existing class.

Another approach will be a Template method for getting the Feeds from the source.


πŸŒ› = 🌜 Metaphor

Pizza making process can be related to the Template method. Overall steps for the process will remain the same it is just that you can modify a step slightly to make a special Pizza for you.

To make an extra cheese pizza you can modify the β€œadd cheese” step and the extra cheese pizza is ready.

πŸŒ“ Talk is cheap. Show me the code

⚑ Define an Abstract class or interface
⚑ Define a default class by implementing the interface.
⚑ Define a template method in the default class. Implementation will contain the sequence of steps to be followed.
⚑ If any variant is required then make a new variant class derived from the default class.


Code Snippet

A Feed instance.

1
2
3
4
5
6
7
struct Feed {
    var title: String
    var description: String
    var category: String
}

1
2
3
4
5
6
7
8
9
10
11
12
13
protocol FeedReader {
    var feeds: [Feed] { get }
    
    func fetchFeeds() async -> [String: String]
    func parseFeeds(rawFeeds: [String: String])
    func categorizeFeeds(feeds: [Feed]) -> [Feed]
    func filterDuplicate(feeds: [Feed]) -> [Feed]
    func sortFeeds(feeds: [Feed]) -> [Feed]
    
    func startFeedReader() async
}

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
class DefaultFeedReader: FeedReader {
    var feeds: [Feed] = []
    
    //Template Method
    func startFeedReader() async {
        let rawFeeds = await self.fetchFeeds()
        self.parseFeeds(rawFeeds: rawFeeds)
        let categorizeFeeds = self.categorizeFeeds(feeds: self.feeds)
        let filterFeeds = self.filterDuplicate(feeds: categorizeFeeds)
        let sortFeeds = self.sortFeeds(feeds: categorizeFeeds)
        
        self.feeds = sortFeeds
    }
    
    //Template methods
    func fetchFeeds() async -> [String: String] {
        //Logic for fetch feed
    }
    
    func parseFeeds(rawFeeds: [String : String]) {
        //Logic for general parse
    }
    
    func categorizeFeeds(feeds: [Feed]) -> [Feed] {
        //Logic for categorize parse
    }
    
    func filterDuplicate(feeds: [Feed]) -> [Feed] {
        //Logic for filter
    }
    
    func sortFeeds(feeds: [Feed]) -> [Feed] {
        //Logic for sort feeds
    }
}

1
2
3
4
5
6
class JsonFeedReader: DefaultFeedReader {
    override func parseFeeds(rawFeeds: [String : String]) {
        //Logic for  parse JSON
    }
}

πŸŒ• Applicability

⚑ It can be applied when you are implementing a process which has a standard sequence of steps to follow.
Example: Compiler designing.

⚑ A functionality which supports multiple types of input can be a good candidate.
Example: parsing XML, JSON, txt, etc, upload data image, image, etc. So most of the steps will be the same only the handling of data will be changed.

A sign-up process has a set of steps which can be fit into the template method. Provide Personal Information, User Interest and User Skills. Based on the user role each step can be modified here.

✨ Trade-offs

Reusability vs Flexibility

Template pattern supports code reusability by moving common code in the base class. On the other hand, It creates a rigid hierarchy of classes. You cannot change the flow and steps in the derived class.

For example, In the above case, The company want to introduce a Pizza with no cheese and no sauce (Healthy Pizza). There is no way to remove the steps here. However, in code, there is a way to achieve this by overriding the method and leaving it empty but then you break the Liskov substitute principle.

Cohesion vs Coupling

Template pattern helps to achieve cohesion in a code by grouping similar functionality in a single place. In the above case, getting feed for the application is at a single place and no dependency will exist on another module to get feeds if structure is followed.

However, on the other hand, it creates a tight coupling between the base class and the subclasses. Any change in the base class will impact the derived class. While designing the base class you need to take care of the interface it should not be too fat.

🌚 Facts

Template & Factory

The Template method may look like the Factory pattern as both have similar designs. However, the Factory pattern is a creational pattern and abstracts the creation logic of similar kinds of objects. On the other hand, a Template pattern is a behavioural design pattern which defines the behaviour of the process.

Question: A template pattern which defines the behaviour of the creation of similar types of Objects can be called a Factory?
Answer: Still, the Template pattern here helps to define the behaviour of the creation of an object not initialize an object for another module. The creation responsibility of the object is still outside of the template method.

Template & Strategy

The template method is used when a standard behaviour exists for a process. The standard behaviour is defined in the base class and variants in a standard behaviour can be added in the subclass.

Strategy pattern is also used to handle multiple variants of a process. However, each variant has independent (No common) implementation. Sorting in most of the language is implemented through this pattern.

This post is licensed under CC BY 4.0 by the author.

Game - Connect Balls

SwiftUI - Create Expandable List (Section Approach)

Comments powered by Disqus.