Привіт! Я знизив ціни на усі продукти. Час разом готувати свої програмерські скіли до пост-COVID-ної ери. Перевірити »
Шаблонний метод

Шаблонний метод на Go

Шаблонний метод — це поведінковий патерн, який визначає кістяк алгоритму в суперкласі та змушує підкласи реалізувати конкретні кроки цього алгоритму.

Концептуальний приклад

Давайте розглянемо приклад функціоналу одноразового пароля (OTP — One Time Password). Він може бути доставлений користувачеві різними шляхами (SMS, електронна пошта і т.ін.), але незалежно від способу доставки, сам процес OTP один і той же:

  1. Створити випадкове число з n-ою кількістю цифр.
  2. Зберегти цей номер у кеш для подальшої верифікації.
  3. Підготувати вміст.
  4. Надіслати сповіщення.

Можливі OTP, які будуть представлені в майбутньому, скоріш за все також будуть використовувати вищевказану процедуру.

У такому випадку кроки конкретної операції однакові, але їхня реалізація може відрізнятися. Така ситуація підходить для використання патерну Шаблонний метод.

Спершу ми визначимо базовий шаблонний алгоритм, який складається з фіксованої кількості методів. Це і буде нашим шаблонним методом. Після цього ми реалізуємо методи для кожного кроку, але шаблонний метод під час цього чіпати не будемо.

otp.go: Шаблонний метод

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: Конкретна реалізація

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: Конкретна реалізація

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: Клієнтський код

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: Результат виконання

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
На основі: Golang By Example

Шаблонний метод іншими мовами програмування

Шаблонний метод на C# Шаблонний метод на C++ Шаблонний метод на Java Шаблонний метод на PHP Шаблонний метод на Python Шаблонний метод на Ruby Шаблонний метод на Rust Шаблонний метод на Swift Шаблонний метод на TypeScript