Using Template Method Pattern we can write part of an algorithm in our implementation and the rest of it is executed in abstraction. So our implementation will replace/rewrite only some steps of the full process.
This article demonstrates Template Method pattern implementations in Golang. Check the following examples and implementation details.
Implementation
Here is a simple example of the Template Method pattern in Golang-
- Create an interface and declare methods that we want to implement later in our implementation. This is our template interface.
- Define a struct for the template, and embed the template interface into it. Define some steps here and define a method that executes all the steps of the full process (in the example below we have named it “process”).
- Define some concrete implementation of the template. Embed the template struct into this. Define the methods that are declared in the template interface.
Here is a simple implementation of the Template Method in Go-
// Template method pattern implementation in Go
package main
import "fmt"
// Template interface
type ITemplate interface {
StepA()
StepB()
}
// Template struct
type Template struct {
ITemplate
}
func NewTemplate(iTemplate ITemplate) (template *Template) {
template = &Template{}
template.ITemplate = iTemplate
return
}
func (template *Template) StepC() {
fmt.Println("Executing Step C of Template")
}
func (template *Template) StepD() {
fmt.Println("Executing Step D of Template")
}
func (template *Template) Process() {
template.ITemplate.StepA()
template.ITemplate.StepB()
template.StepC()
template.StepD()
}
// Concrete implementation
type ConcreteA struct {
*Template
}
func NewConreteA() (concreteA *ConcreteA) {
concreteA = &ConcreteA{}
concreteA.Template = NewTemplate(concreteA)
return
}
func (concreteA *ConcreteA) StepA() {
fmt.Println("Executing Step A of ConcreteA")
}
func (concreteA *ConcreteA) StepB() {
fmt.Println("Executing Step B of ConcreteA")
}
// Concrete implementation
type ConcreteB struct {
*Template
}
func NewConcreteB() (concreteB *ConcreteB) {
concreteB = &ConcreteB{}
concreteB.Template = NewTemplate(concreteB)
return
}
func (concreteA *ConcreteB) StepA() {
fmt.Println("Executing Step A of ConcreteB")
}
func (concreteA *ConcreteB) StepB() {
fmt.Println("Executing Step B of ConcreteB")
}
// Demo
func main() {
concreteA := NewConreteA()
concreteA.Process()
concreteB := NewConcreteB()
concreteB.Process()
}
Output will be as below-
Executing Step A of ConcreteA
Executing Step B of ConcreteA
Executing Step C of Template
Executing Step D of Template
Executing Step A of ConcreteB
Executing Step B of ConcreteB
Executing Step C of Template
Executing Step D of Template
Examples
Here are a few examples of Template Method pattern in GoLang-
Example #1: Transport Construction
Let’s consider an example of transport construction.
Transport Interface and Struct
// transport.go
package main
import "fmt"
type ITransport interface {
CreateBody()
AddEngine()
AddWheel()
// Required only for Plane
AddWing()
}
type Transport struct {
ITransport
}
func NewTransport(iTransport ITransport) (transport *Transport) {
transport = &Transport{}
transport.ITransport = iTransport
return
}
func (transport *Transport) AddSeat() {
// Add seats to the vehicle
// Adding seats are same for all transports so same functions for all
fmt.Println("Adding seats")
}
func (transport *Transport) paint() {
fmt.Println("Painting")
}
func (transport *Transport) Build() {
transport.ITransport.CreateBody()
transport.ITransport.AddEngine()
transport.ITransport.AddWheel()
transport.ITransport.AddWing()
transport.AddSeat()
transport.paint()
}
Car Transport Struct
// car.go
package main
import "fmt"
type Car struct {
*Transport
}
func NewCar() (car *Car) {
car = &Car{}
car.Transport = NewTransport(car)
return
}
func (car *Car) AddEngine() {
fmt.Println("Adding Engine to Car")
}
func (car *Car) AddWheel() {
fmt.Println("Adding 4 Wheels to Car")
}
func (car *Car) AddWing() {
// implementation not require for car
}
func (car *Car) CreateBody() {
fmt.Println("Creating Car Body")
}
Bike Transport Struct
// bike.go
package main
import "fmt"
type Bike struct {
*Transport
}
func NewBike() (bike *Bike) {
bike = &Bike{}
bike.Transport = NewTransport(bike)
return
}
func (bike *Bike) AddEngine() {
fmt.Println("Adding Engine to Bike")
}
func (bike *Bike) AddWheel() {
fmt.Println("Adding 2 Wheels to Bike")
}
func (bike *Bike) AddWing() {
// Implementation not required for bike
}
func (bike *Bike) CreateBody() {
fmt.Println("Creating Bike Body")
}
Plane Transport Struct
// plane.go
package main
import "fmt"
type Plane struct {
*Transport
}
func NewPlane() (plane *Plane) {
plane = &Plane{}
plane.Transport = NewTransport(plane)
return
}
func (plane *Plane) AddEngine() {
fmt.Println("Adding Engine to Plane")
}
func (plane *Plane) AddWheel() {
fmt.Println("Adding 3 Wheels to Plane")
}
func (plane *Plane) AddWing() {
fmt.Println("Adding Wings Plane")
}
func (plane *Plane) CreateBody() {
fmt.Println("Creating Plane Body")
}
Train Transport Struct
// train.go
package main
import "fmt"
type Train struct {
*Transport
}
func NewTrain() (train *Train) {
train = &Train{}
train.Transport = NewTransport(train)
return
}
func (train *Train) AddEngine() {
fmt.Println("Adding Engine to Train")
}
func (train *Train) AddWheel() {
fmt.Println("Adding Wheels to Train")
}
func (train *Train) AddWing() {
// implementatiom not require for train
}
func (train *Train) CreateBody() {
fmt.Println("Creating Train Body")
}
Demo
// main.go
package main
func main() {
car := NewCar()
car.Build()
plane := NewPlane()
plane.Build()
}
Output
Creating Car Body
Adding Engine to Car
Adding 4 Wheels to Car
Adding seats
Painting
Creating Plane Body
Adding Engine to Plane
Adding 3 Wheels to Plane
Adding Wings Plane
Adding seats
Painting
Source Code
Use the following link to get the source code:
Example | Source Code Link |
---|---|
Example #1: Transport Builder | GitHub |
Other Code Implementations
Use the following links to check Template Method pattern implementation in other programming languages.