You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OOP Fortran:如何实现带可变参数初始化的工厂模式

Fortran工厂模式优化:统一形状初始化接口

我尝试基于工厂模式封装形状类型(line_t、rectangle_t、box_t)的创建逻辑,但不同形状的初始化例程参数数量不同(1个、2个、3个),导致主程序仍需用select type分支处理初始化。希望实现主程序仅调用统一的初始化过程,自动适配参数数量并校验参数与形状类型是否匹配。

优化方案

核心思路是将初始化逻辑完全封装到工厂模块内部,通过统一的参数入口+内部类型判断实现适配,同时增加参数数量校验逻辑,避免不匹配的调用。

修改后的完整代码

模块部分

module myModule
    implicit none

    type CFactory
        class(shape_t), pointer :: shape_type => null()
        integer :: shape_choice = 0  ! 记录当前创建的形状类型
    contains
        procedure :: create_shape
        procedure :: init_shape      ! 新增统一初始化方法
        procedure :: cleanup         ! 新增资源清理方法
    end type CFactory

    type, abstract :: shape_t
    contains
        procedure(abstract_print), deferred :: print_size
        ! 定义统一的初始化接口,接受可变长度的实数参数
        generic :: init => init_from_args
        procedure, private :: init_from_args
    end type shape_t

    abstract interface
        subroutine abstract_print(this)
            import shape_t
            class(shape_t), intent(in) :: this
        end subroutine abstract_print
    end interface

    type, extends(shape_t) :: line_t
        real :: length
    contains
        procedure :: print_size => print_linesize
        procedure, private :: init_from_args => init_line
    end type line_t

    type, extends(shape_t) :: rectangle_t
        real :: length, width
    contains
        procedure :: print_size => print_rectanglesize
        procedure, private :: init_from_args => init_rectangle
    end type rectangle_t

    type, extends(shape_t) :: box_t
        real :: length, width, height
    contains
        procedure :: print_size => print_boxsize
        procedure, private :: init_from_args => init_box
    end type box_t

contains

    subroutine create_shape(this, choice)
        class(CFactory), intent(inout) :: this
        integer, intent(in) :: choice

        ! 先清理已有资源
        if (associated(this%shape_type)) call this%cleanup()

        select case (choice)
            case(1)
                allocate(line_t::this%shape_type)
                this%shape_choice = 1
            case(2)
                allocate(rectangle_t::this%shape_type)
                this%shape_choice = 2
            case(3)
                allocate(box_t::this%shape_type)
                this%shape_choice = 3
            case default
                print *, '错误:不支持的形状选择(仅1:线、2:矩形、3:立方体)'
                stop
        end select
    end subroutine create_shape

    subroutine init_shape(this, args)
        class(CFactory), intent(inout) :: this
        real, intent(in) :: args(:)
        integer :: required_args

        ! 校验形状是否已创建
        if (.not.associated(this%shape_type)) then
            print *, '错误:请先调用create_shape创建形状'
            stop
        end if

        ! 校验参数数量是否匹配
        select case(this%shape_choice)
            case(1); required_args = 1
            case(2); required_args = 2
            case(3); required_args = 3
        end select

        if (size(args) /= required_args) then
            print *, '错误:参数数量不匹配,', trim(shape_name(this%shape_choice)), '需要', required_args, '个参数'
            stop
        end if

        ! 调用对应形状的初始化
        call this%shape_type%init(args)
    end subroutine init_shape

    ! 辅助函数:返回形状名称
    function shape_name(choice) result(name)
        integer, intent(in) :: choice
        character(len=10) :: name
        select case(choice)
            case(1); name = '线'
            case(2); name = '矩形'
            case(3); name = '立方体'
            case default; name = '未知形状'
        end select
    end function shape_name

    subroutine cleanup(this)
        class(CFactory), intent(inout) :: this
        if (associated(this%shape_type)) then
            deallocate(this%shape_type)
            this%shape_type => null()
            this%shape_choice = 0
        end if
    end subroutine cleanup

    ! 各形状的初始化实现(接受数组参数)
    subroutine init_line(this, args)
        class(line_t), intent(inout) :: this
        real, intent(in) :: args(:)
        this%length = args(1)
    end subroutine init_line

    subroutine init_rectangle(this, args)
        class(rectangle_t), intent(inout) :: this
        real, intent(in) :: args(:)
        this%length = args(1)
        this%width = args(2)
    end subroutine init_rectangle

    subroutine init_box(this, args)
        class(box_t), intent(inout) :: this
        real, intent(in) :: args(:)
        this%length = args(1)
        this%width = args(2)
        this%height = args(3)
    end subroutine init_box

    ! 打印方法实现
    subroutine print_linesize(this)
        class(line_t), intent(in) :: this
        print *, '线长度:', this%length, '米'
    end subroutine print_linesize

    subroutine print_rectanglesize(this)
        class(rectangle_t), intent(in) :: this
        print *, '矩形面积:', this%length*this%width, '平方米'
    end subroutine print_rectanglesize

    subroutine print_boxsize(this)
        class(box_t), intent(in) :: this
        print *, '立方体体积:', this%length*this%width*this%height, '立方米'
    end subroutine print_boxsize

end module myModule

主程序部分

program main
    use myModule
    implicit none

    type(CFactory) :: factory
    integer :: choice
    real, allocatable :: args(:)

    print *, '请选择形状(1:线、2:矩形、3:立方体)'
    read(*,'(i1)') choice
    call factory%create_shape(choice)

    ! 根据形状类型获取参数
    select case(choice)
        case(1)
            allocate(args(1))
            print *, '请输入线长度:'
            read(*,*) args(1)
        case(2)
            allocate(args(2))
            print *, '请输入矩形的长和宽:'
            read(*,*) args(1:2)
        case(3)
            allocate(args(3))
            print *, '请输入立方体的长、宽、高:'
            read(*,*) args(1:3)
    end select

    ! 统一调用初始化
    call factory%init_shape(args)

    ! 打印信息
    call factory%shape_type%print_size()

    ! 清理资源
    call factory%cleanup()
    deallocate(args)

end program main

关键修改说明

  1. 工厂类增强:新增shape_choice记录当前形状类型,新增init_shape统一初始化方法,内部完成参数数量校验和类型匹配调用。
  2. 统一参数入口:所有形状的初始化方法改为接受实数数组args(:),通过数组长度区分参数数量,避免了不同参数列表的冲突。
  3. 参数校验逻辑:在init_shape中根据shape_choice判断所需参数数量,与输入数组长度对比,不匹配则报错退出。
  4. 资源管理:新增cleanup方法,避免内存泄漏,保证工厂类可重复使用。

主程序简化效果

主程序不再需要select type分支处理初始化,仅需:

  • 创建形状
  • 收集对应数量的参数
  • 调用统一的factory%init_shape(args)

完全隐藏了内部的类型判断和初始化细节,符合工厂模式封装复杂度的设计目标。

内容的提问来源于stack exchange,提问作者Stef1611

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 01:36:25