抛出异常时尝试不同方法的模式

时间:2008-09-24 12:27:03

标签: design-patterns exception exception-handling

这是一个揭示我缺乏经验的问题:我有一个方法 DoSomething(),如果它不能干净地执行它就会引发异常。如果失败了,我会多次尝试不太准确的方法 DoSomethingApproximately(),希望能找到一个足够好的解决方案;如果这也失败了我终于打电话给 DoSomethingInaccurateButGuaranteedToWork()。这三个都是属于这个对象的方法。

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

其次,考虑到它可能引发异常,最好的方法是跟踪我多少次调用 DoSomethingApproximately()?我目前在对象中保留一个变量iNoOfAttempts,并嵌套试块......这太可怕了,我很惭愧。

4 个答案:

答案 0 :(得分:4)

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

在你的情况下,我将这三个方法组合成一个单一的方法,让它返回哪个特定的方法成功,可能有一个枚举或类似的东西。

答案 1 :(得分:2)

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

如果这些方法失败的方式会抛出异常,请在同一方法中捕获所有异常并采取适当的操作,例如增加计数器并返回错误代码。

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

答案 2 :(得分:2)

(伪代码)怎么样:

try{ return doSomething(); }
catch(ExpectedException) { ...not much here probably...}

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

doSomethingGuaranteed();

附录:

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

答案 3 :(得分:2)

在结构路径中转到整个函数指针。只是为了加强它,我会使用一个队列和一些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;
   }
});