什么被认为是“最佳实践” – 以及为什么 – 在构造函数中处理错误?
“最佳实践”可以是Schwartz的报价,或50%的CPAN模块使用它等等;但是,即使解释了为什么常见的最佳做法不是真正的最佳方法,我对任何人的理性意见感到满意.
就我自己对这个主题的看法(通过Perl软件开发多年),Perl模块中出现了三种主要的错误处理方法(在我看来,从最好到最坏)
>构造一个对象,设置一个无效的标志(通常是“is_valid”方法).通常通过类的错误处理与设置错误消息相结合.
优点:
>允许标准(与其他方法调用相比)错误处理,因为它允许在坏构造函数之后使用$obj-> errors()类型调用,就像在任何其他方法调用之后一样.
>允许传递其他信息(例如> 1错误,警告等)
>允许轻量级的“redo”/“fixme”功能,换句话说,如果构造的对象很重,许多复杂的属性总是可以100%,唯一的原因是因为有人进入一个不正确的日期,您可以简单地执行“$obj-> setDate()”,而不是重新执行整个构造函数的开销.这种模式并不总是需要的,但在正确的设计中是非常有用的.
缺点:没有我知道.
>返回“undef”.
缺点:无法实现第一个解决方案的优点(全局变量之外的每个对象错误消息和重型对象的轻量级“fixme”功能).
>在构造函数内死.在一些非常狭窄的边缘案件之外,我个人认为这是一个可怕的选择,有太多的理由列在这个问题的边缘.
>更新:为了清楚,我认为(非常有价值和伟大的设计)解决方案具有非常简单的构造函数,根本不能失败,并且一个重的初始化方法,其中所有的错误检查发生只是一个子集出于此问题的目的,任一情况#1(如果初始化程序设置错误标志)或情况#3(如果初始化程序死机).显然,选择这样的设计,你自动拒绝选项#2.
解决方法
其余的回应是我的个人观察,但是与大多数事情Perl一样,最佳实践真的归结为“这里有一种方法可以根据您的需要进行取舍或离开.”您所描述的您的喜好是完全有效和一致的,否则任何人都不应该告诉你.
实际上,如果构造失败,我宁愿死亡,因为我们设置它,以便在对象构造过程中可能发生的唯一错误类型真的很大,明显的错误应该停止执行.
另一方面,如果你喜欢不会发生,我想我更喜欢2超过1,因为它是一样容易检查一个未定义的对象,因为它是检查一些标志变量.这不是C,所以我们没有强大的打字约束告诉我们,我们的构造函数必须返回一个这样的对象.所以返回undef,并检查它是否建立成败是一个很好的选择.
施工失败的“开销”是某些边缘情况(在发生开销之前不能快速失败)的考虑因素,因此对于那些您可能更喜欢方法1的问题,再次依赖于您为对象定义的语义施工.例如,我喜欢在施工之外进行重量级初始化.对于标准化,我认为检查一个构造函数返回一个定义的对象是否像检查一个标志变量一样好.
编辑:为了回应关于初始化器拒绝#2的编辑,我不明白为什么初始化程序不能简单地返回一个指示成功或失败的值,而不是设置一个标志变量.实际上,您可能希望使用这两者,具体取决于您想要发生的错误的详细程度.但是,如果初始化器在成功时返回true并在失败时返回true,那将是完全有效的.