Autumn SALE
Metoda szablonowa

Metoda szablonowa w języku Go

Metoda szablonowa to behawioralny wzorzec projektowy według którego definiuje się szkielet algorytmu w klasie bazowej i pozwala klasom pochodnym nadpisać poszczególne jego etapy bez zmiany ogólnej struktury.

Przykład koncepcyjny

Weźmy pod uwagę przykład funkcjonalności Haseł Jednorazowych (OTP — One Time Password). Są różne sposoby dostarczenia takiego hasła użytkownikowi (SMS, email, itp.), jednak niezależnie od sposobu cały proces jest taki sam:

  1. Wygeneruj losową n-cyfrową liczbę.
  2. Zapisz wygenerowaną liczbę w pamięci podręcznej w celu późniejszej weryfikacji.
  3. Przygotuj zawartość.
  4. Wyślij powiadomienie.

Ewentualne nowe typy haseł jednorazowych wprowadzone później najprawdopodobniej będą tworzone w analogiczny sposób.

Mamy więc scenariusz w którym etapy pewnej operacji są takie same, a różna jest tylko ich konkretna implementacja. Świetna okazja do posłużenia się wzorcem Metoda szablonowa.

Najpierw definiujemy bazowy szablon algorytmu składający się z pewnej liczby metod. To będzie nasza metoda szablonowa. Następnie zaimplementujemy każdy z etapów, ale pozostawimy metodę szablonową w postaci niezmienionej.

otp.go: Metoda szablonowa

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: Konkretna implementacja

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: Konkretna implementacja

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: Kod klienta

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: Wynik działania

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
Na podstawie: Golang By Example

Metoda szablonowa w innych językach

Metoda szablonowa w języku C# Metoda szablonowa w języku C++ Metoda szablonowa w języku Java Metoda szablonowa w języku PHP Metoda szablonowa w języku Python Metoda szablonowa w języku Ruby Metoda szablonowa w języku Rust Metoda szablonowa w języku Swift Metoda szablonowa w języku TypeScript