【发布时间】:2016-01-26 19:05:15
【问题描述】:
我正在用 Fortran 90/2003 编写一个简短的模块,它提供了一个简单且用户友好的界面,用于计算程序执行的不同部分之间的时间。受Matlab中tic、tac命令的启发,其思路是用户在程序中使用模块如下:
程序测试
使用定时器
调用 Tic("timername")
!一些沉重的东西
调用 Tac("timername")
结束程序测试
现在,我知道我如何可以使用 Fortran 内在函数实现该结果。我的问题是我应该怎么做。我这样做是为了学习好的设计实践,而不是 Fortran 语法。
我定义了一个名为Timer 的用户定义变量,它是我用来实现该功能的主要对象。然而,有(至少)两种不同的方式来使用这个对象让用户使用多个计时器:
a) 我可以将用户定义的变量Timer 公开,然后强制用户手动创建计时器对象。用户必须根据需要创建任意数量的计时器,然后使用方法来处理它们。
b) 我可以通过将其设为私有来隐藏此类型。然后,为了存储不同的定时器,我在模块中创建了一个Timer对象数组作为全局变量,虽然是模块私有的,并且每次用户调用子程序Tic时,都会在这个数组中定义一个新的定时器.在上面的示例中,用户使用的是按照后一种方法实现的模块(请注意,该程序根本没有使用关键字type)。
虽然这两个选项在技术上都有效(我已经实现了这两个选项),但每个选项都有优点和注意事项,而且我所知道的关于软件设计的规则不知何故发生了冲突。我想知道从“正统”的角度来看,哪种方法最好。
选项 a) 具有更好地遵循 OOP 的优点:用户显式地创建对象并使用它进行操作。它不使用任何全局变量。
选项 b) 的优点是“封装”更强。我的意思是用户甚至不需要知道Timer 是什么,甚至不需要知道它的存在。此外,提供与Timer对象交互的接口只是一个简单的字符串,使得整个模块对用户来说更加不透明,不需要特意定义Timer变量。他/她只使用模块提供的两个接受字符串作为输入的子例程。就这样。问题是我觉得这种基于为整个模块定义的数组的设计违背了避免全局变量的规则。它不是真正的全局变量,因为它是私有的,但仍然是。
那么有这两个选项,我应该选择哪一个来产生最正统的方法?
PS:也许还有第三种选择,它允许用户间接创建对象而无需访问用户定义的类型(即,不只是在现有数组中定义元素,如解决方案 b 中所做的那样)。我不知道这是否可以在运行时创建变量。也非常欢迎这方面的任何想法。
【问题讨论】:
-
始终使用标签fortran。如果合适,使用版本标签指定特定版本。请注意,Fortran 90 中没有真正的 OOP,只有一些基本技术是可能的。 True OOP 仅随 Fortran 2003 提供。您确定要将答案限制为仅 Fortran 90 (25 年的语言,比这里的许多人还老!)。
-
您可以将您的模块变量 (b) 放入公共数据类型并传递它。这将允许您拥有多个此类对象,同时保持在其中轻松创建计时器的可能性。这会将负担从创建单个时序对象转移到仅创建一次时序上下文。在这种情况下,您仍然可以使用计时上下文对象的模块变量并将其用作例程中的默认值。
-
@VladimirF 90 和 2003 之间的差异在继承或多态等更高级的特性中变得明显。在这个小模块中,我认为 90 和 2003 没有区别,而让我提出问题的疑惑独立于这个细节层面。因此,我将编辑问题,不要将其限制为 fortran 90。感谢您的提示。
-
@haraldkl 如果我理解你,你描述的场景是 a)。现在我的问题是使用场景 b) 是否更可取,其中模块被更强烈地封装,用户甚至不需要知道 Timer 对象的存在。他/她可以按需创建新的计时器,而无需在程序开始时明确定义它们。从用户的角度来看,选项 b) 更好,但对于使用全局变量可能不是很正统。两者都在技术上工作,但一般来说哪个是最好的设计?这是我的问题。
标签: oop fortran fortran90 fortran2003