推荐一种设计模式/方法来暴露/容忍/从系统错误中恢复,异常处理(例如Java,C ++,Perl,PHP)


13

您能推荐一种设计模式/方法来暴露/容忍/从系统错误中恢复,异常处理(Java,C ++,Perl,PHP)吗?

一些错误需要报告。

某些错误可以在内部处理(通过重试或不重要的处理(可以忽略))。

您如何构造代码以捕获它们?

但是所有错误都需要记录。

有哪些最佳实践?

为了模拟它们能够完全测试受它们影响的组件?

适用于几种现代编程语言的一般非编程语言特定问题,但将欢迎使用Java,C ++,PHP和Perl进行模式,方法和哲学的示例说明。

(也在stackoverflow中问过:https : //stackoverflow.com/questions/7432596/recommend-a-design-pattern-approach-to-exposed-tolerating-recovering-from-system, 但我认为也应该在程序员中提出,因为我认为程序员的问答涵盖了更广泛的软件/编程问题,而stackoverflow则更多地是关于技术实现(IMHO)。


2
对我来说,您的问题似乎过于笼统,开放,无法有效回答。尝试将其限制为某些更特定的情况,以及特定的应用程序类型/环境(例如GUI应用程序/服务器/ ...)。
彼得Török


@péterTörök,mikera提供了一个很好的答案,很可能会接受他们的回答。
therobyouknow 2011年

Answers:


16

快速失败是一种很棒的设计方法,也许可以算作一种模式:http : //en.wikipedia.org/wiki/Fail-fast

我还发现了一些有用的原则:

  • 将异常视为每个功能/模块的接口的一部分 -即记录它们并在适当的地方/如果您的语言支持,请使用检查的异常。
  • 永远不要捏造失败 -如果失败,请不要尝试继续尝试“假设”如何进行。例如,对空情况的特殊处理常常让我感到代码臭味:如果您的方法需要一个非空值,则在遇到空值时应该立即引发异常(NullPointerException或理想情况下更具描述性的IllegalArgumentException)。
  • 编写用于异常情况和正常情况的单元测试 -有时这种测试可能很难设置,但是当您要确保系统对故障具有鲁棒性时,这样做是值得的
  • 在捕获和处理错误的位置记录日志(假设该错误的严重性足以被记录)。这样做的原因是它意味着您了解原因并已采取了处理错误的方法,因此您可以使日志消息有意义.....
  • 仅将异常用于真正的意外情况/故障。如果您的函数以实际预期的方式“失败”(例如,轮询以查看是否有更多输入可用,而找不到任何输入),则它应返回正常响应(“无可用输入”),而不抛出异常
  • 优美地失败(向Steven Lowe致谢!) -在可能的情况下终止之前进行清理,通常是通过撤消更改,回滚事务或释放“ finally”语句或等效语句中的资源。为了清楚和逻辑上的一致性,理想情况下,清理应该在资源投入的同一级别进行。
  • 如果您必须失败,请大声失败 -您的代码的任何部分都无法处理的异常(即渗透到顶层而没有被捕获+处理),这会导致立即,大声和可见的错误,将您的注意力引向它。我通常会暂停程序或任务,并将完整的异常报告写入System.out。

1
也会优雅地失败-如果有可能,请在终止之前进行清理
Steven A. Lowe

+1 @mikera了解要考虑的问题。可能会接受的答案是,我将开放更长的时间供其他人做出贡献。
therobyouknow 2011年

+1 @Steve A. Lowe-以用户为中心的设计。例如,像保存文件一样,不要留下临时文件。在我的问题列表中,将我有关“数据卫生”的问题作为一个相关主题。
therobyouknow 2011年

5

在Java和.NET中处理过异常之后,并阅读了很多有关如何/何时/为什么捕获异常的文章之后,我终于想出了以下步骤,每当我看到潜在的异常发生时,就会想到以下步骤:例外,我必须抓住(Java)...即使它永远不会发生(叹气...)。似乎对我来说至少是有效的:

  1. 除了该异常,我可以做些有用的事情吗(日志记录除外)?如果是,请编写替代方法代码,如果替代方法可能引发异常,请转到2:
  2. 将异常包装在运行时异常周围,将其抛出,转到3。
  3. 在已启动可能的数据库/进程事务的更高级别的类中,捕获异常,回滚事务,然后重新引发异常。
  4. 在顶级类(可能是已启动事务的类)上,使用诸如slf4j(例如,与log4j耦合)或log4net的日志记录框架记录异常。如果可能,直接通过电子邮件将异常发送到由应用程序开发人员组成的通讯组列表。
  5. 如果有GUI,则显示错误消息,以最方便用户的方式指示导致问题的原因;不显示异常/堆栈跟踪,用户不在乎,也不需要知道它是NullPointerException。

我还应该添加步骤0,在由于数据错误而无法执行某些复杂处理的情况下,有意引发所谓的“业务”异常(通过扩展“ Exception”类创建的新异常)。已知会发生,因为它们在分析过程中被确定为例外情况。

除了伐木部分,我完全同意“ mikera”的观点。我只补充说,该异常应该只记录一次

另外,如果您编写的是API / Framework那么我列出的步骤可能会有所不同。在那里,必须抛出精心设计的异常以帮助开发人员了解他们的错误。

至于测试异常,使用模拟对象,您应该能够测试几乎所有内容,无论是否异常,只要您的类尊重“一个类做一件事情”的最佳实践即可。我个人还确保将最重要但隐藏的方法标记为“受保护”而不是“私有”,这样我就可以毫无麻烦地对其进行测试。除此之外,测试异常很简单,只需引发异常并通过捕获它来“期待”异常发生。如果没有异常,则说明单元测试用例错误。


为log4j提及+1 @Jalayn作为一种方法,这是我使用的方法,因此它加强了它以了解其他人的身份。
therobyouknow 2011年

0

以正确的方式构建对象,不必担心外部因素。如果您选择利用异常,请使对象在某些情况下失败时引发异常。

一旦所有对象正常工作,在设计中提出干净的错误处理职责层次结构应该相当容易。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.