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
关键修改说明
- 工厂类增强:新增
shape_choice记录当前形状类型,新增init_shape统一初始化方法,内部完成参数数量校验和类型匹配调用。 - 统一参数入口:所有形状的初始化方法改为接受实数数组
args(:),通过数组长度区分参数数量,避免了不同参数列表的冲突。 - 参数校验逻辑:在
init_shape中根据shape_choice判断所需参数数量,与输入数组长度对比,不匹配则报错退出。 - 资源管理:新增
cleanup方法,避免内存泄漏,保证工厂类可重复使用。
主程序简化效果
主程序不再需要select type分支处理初始化,仅需:
- 创建形状
- 收集对应数量的参数
- 调用统一的
factory%init_shape(args)
完全隐藏了内部的类型判断和初始化细节,符合工厂模式封装复杂度的设计目标。
内容的提问来源于stack exchange,提问作者Stef1611
相关产品推荐
相关产品推荐

