模板方法模式
正文:https://refactoringguru.cn/design-patterns/template-method
Go代码:https://refactoringguru.cn/design-patterns/template-method/go/example
module template_method_module
implicit none
private
public :: otp_type, sms_type, email_type
type, abstract :: iopt_type
contains
procedure(iopt_type_gen_random_opt), deferred :: gen_random_opt
procedure(iopt_type_save_opt_cache), deferred :: save_opt_cache
procedure(iopt_type_get_message), deferred :: get_message
procedure(iopt_type_send_notification), deferred :: send_notification
procedure(iopt_type_publish_metric), deferred :: publish_metric
end type iopt_type
abstract interface
function iopt_type_gen_random_opt(self, len) result(random_opt)
import iopt_type
class(iopt_type), intent(inout) :: self
integer, intent(in) :: len
character(:), allocatable :: random_opt
end function iopt_type_gen_random_opt
subroutine iopt_type_save_opt_cache(self, otp)
import iopt_type
class(iopt_type), intent(inout) :: self
character(*), intent(inout) :: otp
end subroutine iopt_type_save_opt_cache
function iopt_type_get_message(self, otp) result(msg)
import iopt_type
class(iopt_type), intent(inout) :: self
character(*), intent(inout) :: otp
character(:), allocatable :: msg
end function iopt_type_get_message
subroutine iopt_type_send_notification(self, msg)
import iopt_type
class(iopt_type), intent(inout) :: self
character(*), intent(inout) :: msg
end subroutine iopt_type_send_notification
subroutine iopt_type_publish_metric(self)
import iopt_type
class(iopt_type), intent(inout) :: self
end subroutine iopt_type_publish_metric
end interface
! - - - - - - - - - - - - -
type otp_type
class(iopt_type), pointer :: iopt
contains
procedure :: gen_and_send_otp => otp_type_gen_and_send_otp
end type otp_type
type, extends(iopt_type) :: sms_type
contains
procedure :: gen_random_opt => sms_type_gen_random_opt
procedure :: save_opt_cache => sms_type_save_opt_cache
procedure :: get_message => sms_type_get_message
procedure :: send_notification => sms_type_send_notification
procedure :: publish_metric => sms_type_publish_metric
end type sms_type
type, extends(iopt_type) :: email_type
contains
procedure :: gen_random_opt => email_type_gen_random_opt
procedure :: save_opt_cache => email_type_save_opt_cache
procedure :: get_message => email_type_get_message
procedure :: send_notification => email_type_send_notification
procedure :: publish_metric => email_type_publish_metric
end type email_type
contains
subroutine otp_type_gen_and_send_otp(self, otp_length)
class(otp_type), intent(inout) :: self
integer, intent(in) :: otp_length
character(:), allocatable :: otp
character(:), allocatable :: msg
otp = self%iopt%gen_random_opt(otp_length)
call self%iopt%save_opt_cache(otp)
msg = self%iopt%get_message(otp)
call self%iopt%send_notification(msg)
call self%iopt%publish_metric()
end subroutine otp_type_gen_and_send_otp
! - - - - - - - - - -
function sms_type_gen_random_opt(self, len) result(random_opt)
class(sms_type), intent(inout) :: self
integer, intent(in) :: len
character(:), allocatable :: random_opt
random_opt = "1234"
print *, "SMS: generating random otp ", random_opt
end function sms_type_gen_random_opt
subroutine sms_type_save_opt_cache(self, otp)
class(sms_type), intent(inout) :: self
character(*), intent(inout) :: otp
print *, "SMS: saving otp: ", otp, " to cache"
end subroutine sms_type_save_opt_cache
function sms_type_get_message(self, otp) result(msg)
class(sms_type), intent(inout) :: self
character(*), intent(inout) :: otp
character(:), allocatable :: msg
msg = "SMS OTP for login is "//otp
end function sms_type_get_message
subroutine sms_type_send_notification(self, msg)
class(sms_type), intent(inout) :: self
character(*), intent(inout) :: msg
print *, "SMS: sending sms: "//msg
end subroutine sms_type_send_notification
subroutine sms_type_publish_metric(self)
class(sms_type), intent(inout) :: self
print *, "SMS: publishing metric"
end subroutine sms_type_publish_metric
! - - - - - - - - - -
function email_type_gen_random_opt(self, len) result(random_opt)
class(email_type), intent(inout) :: self
integer, intent(in) :: len
character(:), allocatable :: random_opt
random_opt = "1234"
print *, "EMAIL: generating random otp ", random_opt
end function email_type_gen_random_opt
subroutine email_type_save_opt_cache(self, otp)
class(email_type), intent(inout) :: self
character(*), intent(inout) :: otp
print *, "EMAIL: saving otp: ", otp, " to cache"
end subroutine email_type_save_opt_cache
function email_type_get_message(self, otp) result(msg)
class(email_type), intent(inout) :: self
character(*), intent(inout) :: otp
character(:), allocatable :: msg
msg = "EMAIL OTP for login is "//otp
end function email_type_get_message
subroutine email_type_send_notification(self, msg)
class(email_type), intent(inout) :: self
character(*), intent(inout) :: msg
print *, "EMAIL: sending email: "//msg
end subroutine email_type_send_notification
subroutine email_type_publish_metric(self)
class(email_type), intent(inout) :: self
print *, "EMAIL: publishing metric"
end subroutine email_type_publish_metric
end module template_method_module
program template_method_main
use template_method_module, only: otp_type, sms_type, email_type
type(otp_type) :: otp
type(sms_type), target :: sms_otp
type(email_type), target :: email_otp
sms_otp = sms_type()
otp%iopt => sms_otp
call otp%gen_and_send_otp(4)
write (*, *)
email_otp = email_type()
otp%iopt => email_otp
call otp%gen_and_send_otp(4)
end program template_method_main
!> Results shall be:
! SMS: generating random otp 1234
! SMS: saving otp: 1234 to cache
! SMS: sending sms: SMS OTP for login is 1234
! SMS: publishing metric
!
! EMAIL: generating random otp 1234
! EMAIL: saving otp: 1234 to cache
! EMAIL: sending email: EMAIL OTP for login is 1234
! EMAIL: publishing metric