Summer SALE
Template Method

Template Method in Go

Template Method is a behavioral design pattern that allows you to define a skeleton of an algorithm in a base class and let subclasses override the steps without changing the overall algorithm’s structure.

Conceptual Example

Let’s consider the example of One Time Password (OTP) functionality. There are different ways that the OTP can be delivered to a user (SMS, email, etc.). But irrespective whether it’s an SMS or email OTP, the entire OTP process is the same:

  1. Generate a random n digit number.
  2. Save this number in the cache for later verification.
  3. Prepare the content.
  4. Send the notification.

Any new OTP types that will be introduced in the future most likely still go through the above steps.

So, we have a scenario where the steps of a particular operation are the same, but these steps’ implementation may differ. This is an appropriate situation to consider using the Template Method pattern.

First, we define a base template algorithm that consists of a fixed number of methods. That’ll be our template method. We will then implement each of the step methods, but leave the template method unchanged.

otp.go: Template method

package main type IOtp interface {	genRandomOTP(int) string	saveOTPCache(string)	getMessage(string) string	sendNotification(string) error } // type otp struct { // } // func (o *otp) genAndSendOTP(iOtp iOtp, otpLength int) error { //	otp := iOtp.genRandomOTP(otpLength) //	iOtp.saveOTPCache(otp) //	message := iOtp.getMessage(otp) //	err := iOtp.sendNotification(message) //	if err != nil { //	return err //	} //	return nil // } type Otp struct {	iOtp IOtp } func (o *Otp) genAndSendOTP(otpLength int) error {	otp := o.iOtp.genRandomOTP(otpLength)	o.iOtp.saveOTPCache(otp)	message := o.iOtp.getMessage(otp)	err := o.iOtp.sendNotification(message)	if err != nil {	return err	}	return nil } 

sms.go: Concrete implementation

package main import "fmt" type Sms struct {	Otp } func (s *Sms) genRandomOTP(len int) string {	randomOTP := "1234"	fmt.Printf("SMS: generating random otp %s\n", randomOTP)	return randomOTP } func (s *Sms) saveOTPCache(otp string) {	fmt.Printf("SMS: saving otp: %s to cache\n", otp) } func (s *Sms) getMessage(otp string) string {	return "SMS OTP for login is " + otp } func (s *Sms) sendNotification(message string) error {	fmt.Printf("SMS: sending sms: %s\n", message)	return nil } 

email.go: Concrete implementation

package main import "fmt" type Email struct {	Otp } func (s *Email) genRandomOTP(len int) string {	randomOTP := "1234"	fmt.Printf("EMAIL: generating random otp %s\n", randomOTP)	return randomOTP } func (s *Email) saveOTPCache(otp string) {	fmt.Printf("EMAIL: saving otp: %s to cache\n", otp) } func (s *Email) getMessage(otp string) string {	return "EMAIL OTP for login is " + otp } func (s *Email) sendNotification(message string) error {	fmt.Printf("EMAIL: sending email: %s\n", message)	return nil } 

main.go: Client code

package main import "fmt" func main() {	// otp := otp{}	// smsOTP := &sms{	//	otp: otp,	// }	// smsOTP.genAndSendOTP(smsOTP, 4)	// emailOTP := &email{	//	otp: otp,	// }	// emailOTP.genAndSendOTP(emailOTP, 4)	// fmt.Scanln()	smsOTP := &Sms{}	o := Otp{	iOtp: smsOTP,	}	o.genAndSendOTP(4)	fmt.Println("")	emailOTP := &Email{}	o = Otp{	iOtp: emailOTP,	}	o.genAndSendOTP(4) } 

output.txt: Execution result

SMS: generating random otp 1234 SMS: saving otp: 1234 to cache SMS: sending sms: SMS OTP for login is 1234 EMAIL: generating random otp 1234 EMAIL: saving otp: 1234 to cache EMAIL: sending email: EMAIL OTP for login is 1234 

Template Method in Other Languages

Template Method in C# Template Method in C++ Template Method in Java Template Method in PHP Template Method in Python Template Method in Ruby Template Method in Rust Template Method in Swift Template Method in TypeScript