Summer SALE
템플릿 메서드

Go로 작성된 템플릿 메서드

템플릿 메서드는 기초 클래스에서 알고리즘의 골격을 정의할 수 있도록 하는 행동 디자인 패턴입니다. 또 이 패턴은 자식 클래스들이 전체 알고리즘의 구조를 변경하지 않고도 기본 알고리즘의 단계들을 오버라이드할 수 있도록 합니다.

개념적인 예시

OTP(One Time Password) 일회용 비밀번호 기능의 예시를 살펴봅시다. 사용자에 OTP를 전달하는 방법은 여러 가지가 있습니다​(SMS, 이메일 등). 그러나 방법​(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

다른 언어로 작성된 템플릿 메서드

C#으로 작성된 템플릿 메서드C++로 작성된 템플릿 메서드자바로 작성된 템플릿 메서드PHP로 작성된 템플릿 메서드파이썬으로 작성된 템플릿 메서드루비로 작성된 템플릿 메서드러스트로 작성된 템플릿 메서드스위프트로 작성된 템플릿 메서드타입스크립트로 작성된 템플릿 메서드