【问题标题】:Exceptions and Abstractions异常和抽象
【发布时间】:2009-07-05 13:02:41
【问题描述】:

什么时候应该抛出自定义异常?

例如我有一些连接到服务器的代码。连接到服务器的代码在连接失败时会抛出 IOException。在它被调用的方法的上下文中,这很好。在网络代码中也可以。

但是由于这表示没有连接(因此无法正常工作),所以异常一直到 ui。在这个阶段,一个 IOException 是非常模棱两可的。像 NoConnectionException 这样的东西会更好。

所以,我的问题是: 您应该在什么阶段捕获一个异常,而不是抛出另一个更适合抽象的(自定义)异常?

【问题讨论】:

标签: language-agnostic exception abstraction


【解决方案1】:

我希望异常会根据我要求原始方法执行的操作来讨论。例如

read -> ReadException
connect -> ConnectException
buildPortfolio -> FailedToBuildPortfolioException

等等。这将抽象出幕后发生的事情(即您是否通过套接字等进行连接)。作为一般规则,当我为组件创建接口时,我通常会创建相应的异常或一组异常。我的接口将被称为Component,我的例外通常是ComponentException(例如RateSourceRateSourceException)。作为一个完整的组件集导出到不同的项目是一致且容易的。

缺点是您创建了很多异常,并且您可能需要执行很多翻译。好处是(正如您已经确定的)您几乎没有抽象泄漏。

在方法调用(以及异常)的层次结构中的某个时刻,您可能会决定无法进行恢复(或者它位于不适当的位置)并转换为未经检查的异常以供以后处理。

【讨论】:

  • 我不会创建大量异常 - 每个方法的异常太多了。创建一些通用异常类型并在异常中传递消息。您可以获得同样多的灵活性,并且不会因为过多的异常类而使代码变得混乱。
  • 不是每个方法。它(通常)是每个组件。那个组件可以有一个方法,或者二十个。
【解决方案2】:

我知道这被标记为“与语言无关”,但我认为并非如此。从 C++ 的角度来看,我预计很少有基本操作会引发异常 - C++ 标准库仅在极少数地方使用异常。所以我自己的代码往往是最先产生异常的地方。在那个代码中,我喜欢一个非常扁平的层次结构——我不想在后面的代码中弄乱数百个 catch() 子句,并且从来没有理解 Java 和 C# 明显痴迷于创建类和命名空间的巴洛克层次结构。

因此,对于我的 C++ 代码 - 一种异常类型,每个库都包含有意义的错误消息。一个用于最终的可执行文件。

【讨论】:

    【解决方案3】:

    我认为这里隐藏了两个问题: a) 什么时候应该将一个异常隐藏在另一个异常后面。 b) 什么时候应该为此使用自定义异常。

    a) 我想说:当异常跨越应用程序中的两层边界时,它应该隐藏在更适合新层的异常后面。 示例:因为您正在执行一些远程操作,所以会收到 ConnectionWhatEverException。

    但是调用者不应该知道连接问题。因为他只是想执行一些服务,所以他得到了一个 ServiceOutOfOrderException。这样做的原因是:在层内部,进行远程处理时,您可能会使用 ConnectionException 做一些有用的事情(重试,写入回退队列......)。一旦你离开了那个层,没有人知道如何处理 ConnectionException。但是当服务不工作时,他们应该能够决定做什么。

    b) 当没有匹配的现有异常时。例如,Java 中有几个有用的异常。我经常使用 IllegalState 和 IllegalArgument。一个新的异常类的一个强有力的论据是,如果你有一些有用的上下文要提供。例如,失败的服务的名称可能是 ServiceFailedException 的参数。只是不要为每个方法调用或任何类似的方法创建一个类。 100 个异常类不是问题,只要它们具有不同的行为(即至少不同的字段)。如果它们仅在名称上有所不同并且位于相同的抽象级别,则将它们设为一个异常,并将不同的名称放在消息中或该异常类的单个字段中。

    c) 至少在 java 中有关于检查异常的讨论。我将它们直接包装在未检查的中,因为我讨厌检查的那种。但这更像是一种意见而不是建议。

    【讨论】:

      【解决方案4】:

      在任何情况下您会得到不是由 IO 问题引起的 NoConnectionException 吗?相反,知道原因是否基于 IO 是否有助于客户明智地恢复?

      【讨论】:

      • ATM,它仅由 IO 问题引发。它不会帮助客户,即使它知道它是基于 IO 的。
      【解决方案5】:

      什么时候应该抛出自定义异常?

      我。当您可以提供更多(诊断)信息时。

      注意:在引发原始异常 (IOException) 的地方可能无法获得此附加信息。渐进式抽象层可能需要添加更多信息,例如您尝试执行的操作导致了此异常?

      二。当您不能公开实现细节时:即您希望(幻想?)抽象继续。

      当底层实现机制可能发生变化时,这可能很重要。将底层异常包装在自定义异常中是将您的客户与实现细节隔离开来的好方法(通过提升抽象级别)

      三。 I和II都

      注意:此外,您的客户应该能够调整到他们感兴趣的确切信息级别,或者他们应该能够调整他们不感兴趣的任何内容。因此,最好从异常。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-05-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-02
        相关资源
        最近更新 更多