Introduction
The template method pattern is a behavourial design pattern which allows you to define the template, or the skeleton of an operation in a base class, while allowing the subclasses to override specific steps or all steps of the algorithm without changing its structure.
This pattern is very useful when you have a series of steps that needs to be performed in a specific order, but you need different implementations in different situations.
So, what does it look like? Well, like this:
A short explanation:
- The Producer is tasked with producing some product, which in this case can be a Car or a Bike. In order to produce these products, two steps are needed.
- BikeProducer and CarProducer are the two concrete Producers.
- The Client class both the step1 and the step2 method to obtain a product.
Since Go does not support the notion of superclasses or abstract classes, we can implement this with interfaces.
Implementation in Go
Open your terminal or commandline in an empty directory and type:
go mod init github.com/designpatterns_template
Add a main.go file and type the following:
package main
import "fmt"
We need a template for the production of our vehicles:
type Template interface {
AddFrame()
AddWheels()
}
Now we will introduce the CarProducer. As you can see, this is an empty struct as we do not need any date in this simple example:
type CarProducer struct{}
func (c *CarProducer) AddFrame() {
fmt.Println("Adding car frame")
}
func (c *CarProducer) AddWheels() {
fmt.Println("Adding 4 wheels")
}
The two methods are self-explanatory, as they do nothing but print out some information.
The BikeProducer is similar:
type BikeProducer struct{}
func (c *BikeProducer) AddFrame() {
fmt.Println("Adding bike frame")
}
func (c *BikeProducer) AddWheels() {
fmt.Println("Adding 2 wheels")
}
Now we need a method to actually produce the vehicle. This only takes an object which implements the Template interface as a parameter:
func ProduceVehicle(template Template) {
template.AddWheels()
template.AddFrame()
}
Now it is time to test it all:
func main() {
template := &BikeProducer{}
ProduceVehicle(template)
}
Line by line:
- We instatiate a BikeProducer struct. This struct implements the Template interface.
- We produce the Vehicle, either a Bike or a Car. What is noticeable that the actual production process, such as it is in this example, is complete unknown to the client.
Conclusion
The implementation of this pattern in Go is quite straightforward, and the usage of interfaces also makes this implementation quite elegant.