【问题标题】:Pattern for trying different methods when exception is thrown抛出异常时尝试不同方法的模式
【发布时间】:2008-09-24 12:27:02
【问题描述】:

这是一个暴露我缺乏经验的问题:我有一个方法 DoSomething() 如果它不能干净地完成它,它会抛出异常。如果失败,我尝试了几次不太准确的方法DoSomethingApproximately(),希望它能找到一个足够好的解决方案;如果这也失败了,我最后会调用 DoSomethingInaccurateButGuaranteedToWork()。这三个都是属于这个对象的方法。

两个问题:首先,这种(确实丑陋的)模式是否可以接受,还是有更优雅的方式?

其次,什么是跟踪我调用 DoSomethingApproximately() 次数的最佳方法,因为它可能会引发异常?我目前在对象中保留一个变量 iNoOfAttempts,并嵌套 try 块......这太可怕了,我很惭愧。

【问题讨论】:

  • 是的;我认为大多数解决方案都应该与语言无关,只要可以进行异常处理。

标签: design-patterns exception exception-handling


【解决方案1】:

您不应该在应用程序的控制流中使用异常。

在您的情况下,我会将这三个方法组合成一个方法,并让它返回成功的特定方法,可能使用枚举或类似的东西。

【讨论】:

  • 我不同意。如果 DoSomethingApproximately() 和 DoSomethingThatAlwaysWorks() 实际上是错误处理函数,那么异常很可能是执行此操作的适当方法。
  • 异常将在意外情况下抛出,而不是在预期错误中。当然,这条规则也有例外。
  • 是的,当然。我们必须假设 DoSomething() 做了它应该做的事情,除非发生了意想不到的事情......;)
  • 不,我们不能假设任何事情。提问者甚至似乎期望该方法会失败......
  • 除此之外,您必须小心不要隐藏实际问题而非“预期”问题的异常。无论如何,+1 不要使用异常来控制流量。
【解决方案2】:

返回错误代码而不是抛出异常。

如果这些方法失败的方式确实会引发异常,请在同一个方法中捕获它们并采取适当的措施,例如增加计数器并返回错误代码。

   bool result = DoSomething();
   while (!result && tries < MAX_TRIES) {
       result = DoSomethingApproximately(); //This will increment tries
       if (tries > THRESHOLD) {
           result = DoSomethingThatAlwaysWorks();
       }
   }

【讨论】:

    【解决方案3】:

    将整个函数指针放在结构路径中。为了增加趣味,我将使用队列和一些 LINQ。

    Queue<Action> actions = new Queue<Action>(new Action[] {
       obj.DoSomething,
       obj.DoSomethingApproximately,
       obj.DoSomethingApproximately,
       obj.DoSomethingApproximately,
       obj.DoSomethingApproximately,
       obj.DoSomethingGuaranteed
    });
    
    actions.First(a => {
       try {
          a();
          return true;
       } catch (Exception) {
          return false;
       }
    });
    

    【讨论】:

      【解决方案4】:

      怎么样(伪代码):

      try{ return doSomething(); }
      catch(ExpectedException) { ...not much here probably...}
      
      for(i = 0 to RETRIES){
      try{ return doSomethingApproximately; }
      catch(ExpectedException) { ...not much here probably...}
      }
      
      doSomethingGuaranteed();
      

      附录:

      我强烈建议您不要使用特殊的返回值,因为这意味着该函数的每个用户都必须知道某些返回值是特殊的。根据函数的范围,返回可以正常处理的范围的普通部分可能是明智的,例如一个空集合。当然,这可能无法区分失败和“正确”答案是空集合(在本例中)。

      【讨论】:

      • 我有时喜欢有一个参数来允许调用者指示常见的故障模式是否应该通过异常或返回码来指示。考虑类似“使用凭证 Y 登录服务器 X”。如果调用者期望尝试可能会失败(例如,如果它有一个服务器列表,并且会尝试直到成功)让方法抛出异常是没有帮助的。另一方面,如果代码期望登录能够简单地工作,则抛出异常可能会消除对尝试进行客户端错误检查的需要,如果抛出的异常是客户端可以捕获的异常。
      猜你喜欢
      • 2023-03-25
      • 2020-11-11
      • 2022-06-12
      • 1970-01-01
      • 1970-01-01
      • 2020-09-18
      • 2011-11-23
      • 2015-07-16
      • 2021-02-08
      相关资源
      最近更新 更多