工厂模式

正文:https://refactoringguru.cn/design-patterns/factory

Go代码:https://refactoringguru.cn/design-patterns/factory/go/example

module factory_module

    use, intrinsic :: iso_fortran_env, only: int8
    implicit none
    private

    public :: igun_type, ak47_type, musket_type, get_gun

    type, abstract :: igun_type
    contains
        procedure(igun_type_set_name), deferred :: set_name
        procedure(igun_type_set_power), deferred :: set_power
        procedure(igun_type_get_name), deferred :: get_name
        procedure(igun_type_get_power), deferred :: get_power
    end type igun_type

    abstract interface

        subroutine igun_type_set_name(self, name)
            import igun_type
            class(igun_type), intent(inout) :: self
            character(*), intent(in) :: name
        end subroutine igun_type_set_name

        subroutine igun_type_set_power(self, power)
            import igun_type, int8
            class(igun_type), intent(inout) :: self
            integer(int8), intent(in) :: power
        end subroutine igun_type_set_power

        function igun_type_get_name(self) result(name)
            import igun_type
            class(igun_type), intent(inout) :: self
            character(:), allocatable :: name
        end function igun_type_get_name

        function igun_type_get_power(self) result(power)
            import igun_type, int8
            class(igun_type), intent(inout) :: self
            integer(int8) :: power
        end function igun_type_get_power

    end interface

    type, extends(igun_type) :: gun_type
        character(:), allocatable :: name
        integer(int8) :: power
    contains
        procedure :: set_name => gun_type_set_name
        procedure :: get_name => gun_type_get_name
        procedure :: set_power => gun_type_set_power
        procedure :: get_power => gun_type_get_power
    end type gun_type

    type, extends(gun_type) :: ak47_type
    end type ak47_type

    type, extends(gun_type) :: musket_type
    end type musket_type

contains

    subroutine gun_type_set_name(self, name)
        class(gun_type), intent(inout) :: self
        character(*), intent(in) :: name
        self%name = name
    end subroutine gun_type_set_name

    subroutine gun_type_set_power(self, power)
        class(gun_type), intent(inout) :: self
        integer(int8), intent(in) :: power
        self%power = power
    end subroutine gun_type_set_power

    function gun_type_get_name(self) result(name)
        class(gun_type), intent(inout) :: self
        character(:), allocatable :: name
        name = self%name
    end function gun_type_get_name

    function gun_type_get_power(self) result(power)
        class(gun_type), intent(inout) :: self
        integer(int8) :: power
        power = self%power
    end function gun_type_get_power

    function get_gun(gun_type) result(igun)
        character(*), intent(in) :: gun_type
        class(igun_type), allocatable :: igun

        select case (gun_type)
        case ("ak47")
            igun = ak47_type(name="ak47 gun", power=4)
        case ("musket")
            igun = musket_type(name="musket gun", power=1)
        case default
            error stop "*ERROR* `gnu_type` not supported"
        end select

    end function get_gun

end module factory_module
program factory_main

    use factory_module, only: igun_type, ak47_type, musket_type, get_gun
    implicit none

    class(igun_type), allocatable :: ak47, musket

    allocate (ak47_type :: ak47)
    allocate (musket_type :: musket)

    ak47 = get_gun("ak47")
    musket = get_gun("musket")

    call print_details(ak47)
    call print_details(musket)

contains

    subroutine print_details(igun)
        class(igun_type), intent(inout) :: igun
        print *, "Gun: ", igun%get_name()
        print *, "Power: ", igun%get_power()
    end subroutine print_details

end program factory_main

!> Results shall be:

!  Gun: ak47 gun
!  Power:     4
!  Gun: musket gun
!  Power:     1