访问者模式
正文:https://refactoringguru.cn/design-patterns/visitor
Go代码:https://refactoringguru.cn/design-patterns/visitor/go/example
!> Reference: https://refactoring.guru/design-patterns/visitor/go/example
module visitor_pattern
implicit none
private
public :: square_type, circle_type, rectangle_type, area_calculator_type, middle_coordinates_type
!> Two abstract classes
type, abstract :: shape
contains
procedure(get_type_procedure), deferred :: get_type
procedure(accept_procedure), deferred :: accept
end type shape
type, abstract :: visitor
contains
procedure(visit_procedure), deferred :: visit
end type visitor
abstract interface
function get_type_procedure(self) result(result)
import shape
class(shape), intent(inout) :: self
character(:), allocatable :: result
end function get_type_procedure
subroutine accept_procedure(self, v)
import shape, visitor
class(shape), intent(inout) :: self
class(visitor), intent(inout) :: v
end subroutine accept_procedure
subroutine visit_procedure(self, s)
import visitor, shape
class(visitor), intent(inout) :: self
class(shape), intent(inout) :: s
end subroutine visit_procedure
end interface
!> Specific shapes
type, extends(shape) :: square_type
integer :: side
contains
procedure :: get_type => square_get_type
procedure :: accept => square_accept
end type square_type
type, extends(shape) :: circle_type
integer :: radius
contains
procedure :: get_type => circle_get_type
procedure :: accept => circle_accept
end type circle_type
type, extends(shape) :: rectangle_type
integer :: l
integer :: b
contains
procedure :: get_type => rectangle_get_type
procedure :: accept => rectangle_accept
end type rectangle_type
!> Specific visitors
type, extends(visitor) :: area_calculator_type
integer :: area
contains
procedure :: visit => area_calculator_visit
end type area_calculator_type
type, extends(visitor) :: middle_coordinates_type
integer :: x, y
contains
procedure :: visit => middle_coordinates_visit
end type middle_coordinates_type
contains
function square_get_type(self) result(result)
class(square_type), intent(inout) :: self
character(:), allocatable :: result
result = "Square"
end function square_get_type
function circle_get_type(self) result(result)
class(circle_type), intent(inout) :: self
character(:), allocatable :: result
result = "Circle"
end function circle_get_type
function rectangle_get_type(self) result(result)
class(rectangle_type), intent(inout) :: self
character(:), allocatable :: result
result = "Rectangle"
end function rectangle_get_type
subroutine square_accept(self, v)
class(square_type), intent(inout) :: self
class(visitor), intent(inout) :: v
call v%visit(self)
end subroutine square_accept
subroutine circle_accept(self, v)
class(circle_type), intent(inout) :: self
class(visitor), intent(inout) :: v
call v%visit(self)
end subroutine circle_accept
subroutine rectangle_accept(self, v)
class(rectangle_type), intent(inout) :: self
class(visitor), intent(inout) :: v
call v%visit(self)
end subroutine rectangle_accept
subroutine area_calculator_visit(self, s)
class(area_calculator_type), intent(inout) :: self
class(shape), intent(inout) :: s
select type (s)
type is (square_type)
print *, "Calculating area for square.🔥"
type is (circle_type)
print *, "Calculating area for circle.🔥"
type is (rectangle_type)
print *, "Calculating area for rectangle.🔥"
end select
end subroutine area_calculator_visit
subroutine middle_coordinates_visit(self, s)
class(middle_coordinates_type), intent(inout) :: self
class(shape), intent(inout) :: s
select type (s)
type is (square_type)
print *, "Calculating middle point coordinates for square.💠"
type is (circle_type)
print *, "Calculating middle point coordinates for circle.💠"
type is (rectangle_type)
print *, "Calculating middle point coordinates for rectangle.💠"
end select
end subroutine middle_coordinates_visit
end module visitor_pattern
!> Reference: https://refactoring.guru/design-patterns/visitor/go/example
program test_visitor
use visitor_pattern, only: square_type, circle_type, rectangle_type, area_calculator_type, middle_coordinates_type
type(square_type) :: s = square_type(side=2)
type(circle_type) :: c = circle_type(radius=3)
type(rectangle_type) :: r = rectangle_type(l=2, b=3)
type(area_calculator_type) :: a
type(middle_coordinates_type) :: m
!> area_calculator visiting shapes
call s%accept(a)
call c%accept(a)
call r%accept(a)
!> middle_coordinates visiting shapes
call s%accept(m)
call c%accept(m)
call r%accept(m)
!> Getting type of shape
print *, s%get_type()
print *, c%get_type()
print *, r%get_type()
end program test_visitor
!> Results shall be:
! Calculating area for square.🔥
! Calculating area for circle.🔥
! Calculating area for rectangle.🔥
! Calculating middle point coordinates for square.💠
! Calculating middle point coordinates for circle.💠
! Calculating middle point coordinates for rectangle.💠
! Square
! Circle
! Rectangle