Design patterns 用于在引发异常时尝试不同方法的模式

Design patterns 用于在引发异常时尝试不同方法的模式,design-patterns,exception,exception-handling,Design Patterns,Exception,Exception Handling,这里有一个问题暴露了我的经验不足:我有一个方法DoSomething(),如果它不能干净地完成,就会抛出一个异常。如果失败了,我尝试了几次精度较低的方法dosomethingapproximaly(),希望它能找到一个足够好的解决方案;如果这也失败了,我最终会调用doSomethingAccuratedBuaredToWork()。这三种方法都属于此对象 两个问题:首先,这种(公认丑陋的)模式可以接受吗,还是有更优雅的方式 其次,考虑到可能引发异常,跟踪我调用了多少次doSomethingApp

这里有一个问题暴露了我的经验不足:我有一个方法DoSomething(),如果它不能干净地完成,就会抛出一个异常。如果失败了,我尝试了几次精度较低的方法dosomethingapproximaly(),希望它能找到一个足够好的解决方案;如果这也失败了,我最终会调用doSomethingAccuratedBuaredToWork()。这三种方法都属于此对象

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


其次,考虑到可能引发异常,跟踪我调用了多少次doSomethingApproximaly()的最佳方法是什么?我目前在对象中保留一个变量iNoOfAttempts,并嵌套try块。。。这太可怕了,我感到羞愧

返回错误代码,而不是引发异常

如果这些方法失败,那么抛出异常,在同一个方法中捕获它们并采取适当的措施,比如增加计数器并返回错误代码

   bool result = DoSomething();
   while (!result && tries < MAX_TRIES) {
       result = DoSomethingApproximately(); //This will increment tries
       if (tries > THRESHOLD) {
           result = DoSomethingThatAlwaysWorks();
       }
   }
bool result=DoSomething();
而(!结果和尝试次数<最大尝试次数){
result=dosomethingapproximaly();//这将增加尝试次数
如果(尝试>阈值){
结果=DoSomethingThatAlwaysWorks();
}
}

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

在您的例子中,我将三个方法组合成一个方法,并让它返回哪种方法成功,可能是使用枚举或类似的方法。

如何(伪代码):

增编:


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

在结构路由中遍历整个函数指针。为了增加趣味性,我将使用一个队列和一些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;
   }
});
Queue actions=new Queue(new Action[]{
对象。DoSomething,
目标剂量大致相同,
目标剂量大致相同,
目标剂量大致相同,
目标剂量大致相同,
目标剂量保证
});
首先(a=>{
试一试{
a();
返回true;
}捕获(例外){
返回false;
}
});

是;我认为,只要异常处理是可能的,大多数解决方案都应该是与语言无关的。如果DoSomethingApproximately()和doSomethingHatalwaysworks()实际上是错误处理函数,那么异常很可能是正确的方法。异常将在意外情况下抛出,而不是在预期的错误中抛出。当然,这条规则也有例外。是的,当然。我们必须假设DoSomething()做了它应该做的事情,除非发生意外情况……;)不,我们不能假设什么。提问者甚至似乎期望该方法会失败……除此之外,你必须小心,不要隐藏实际问题而非“预期”问题的异常。不管怎样,+1不使用异常进行流量控制。我有时喜欢使用一个参数,允许调用方指示是否应通过异常或返回代码指示常见故障模式。考虑“登录到服务器X,凭据Y”之类的东西。如果调用方预期尝试可能失败(例如,如果它有一个服务器列表,并将一直尝试直到成功),则让该方法引发异常是没有帮助的。另一方面,如果代码希望登录可以简单地工作,那么如果抛出的异常是客户端可以捕获的异常,则抛出异常可以消除在尝试时进行客户端错误检查的需要。
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;
   }
});