2009-12-03 58 views
0

我目前正在重構一個使用邏輯流異常的應用程序。該代碼很難閱讀和維護,並使得像我這樣的S.O.L.I.D迷迷們在閱讀時哭泣(更不用提我在職業生涯中見過的最長的catch block)。工作流的重構例外

我的問題是你可以使用什麼樣的模式來使它更容易維護或你將如何去重構?

public void CallExternalServices(ICriteria criteria) 
{ 
    try 
    { 
     someResult = ExternalService1.SomeMethod(criteria); 
    } 
    catch (Service1Exception service1Exception) 
    { 
     if (criteria.SomeValue == "1") 
     { 
      if (service1Exception.InnerException != null 
       && service1Exception.InnerException.InnerException != null 
       && service1Exception.InnerException.InnerException is TargetSystemException) 
      { 
       TargetSystemException targetSystemException = (TargetSystemException)service1Exception.InnerException.InnerException; 
       if (targetSystemException.ErrorStatus.IsServiceDownForMaintenance()) 
       { 
        // Call internal method to perform some action 
        SendNotification("Service down for maintenance.") 
       } 
      } 
     } 
     else if (criteria.SomeValue == "2") 
     { 
      if (service1Exception.InnerException != null 
       && service1Exception.InnerException.InnerException != null 
       && service1Exception.InnerException.InnerException is TargetSystemException) 
      { 
       TargetSystemException tx = (TargetSystemException)service1Exception.InnerException.InnerException; 
       if (targetSystemException.ErrorStatus.IsBusy()) 
       { 
        // Call to some internal method to perform an action 
        SendDifferentNotification() 

        criteria.SetSomeFlagToBe = true; 

        try 
        { 
         someResult = ExternalService2.SomeOtherMethod(criteria); 
        } 
        catch (Service2Exception service2Exception) 
        { 
         if (service2Exception.InnerException != null 
          && service2Exception.InnerException.InnerException != null 
          && service2Exception.InnerException.InnerException is TargetSystemException) 
         { 
          TargetSystemException tx = (TargetSystemException)service1Exception.InnerException.InnerException; 
          if (targetSystemException.ErrorStatus.HasNumberOfDailyTransactionsBeenExceeded()) 
          { 
           // Call internal method to perform some action 
           SendNotification("Number of daily transactions exceeded.") 
          } 
         } 
         else if (service2Exception.InnerException != null 
          && service2Exception.InnerException.InnerException != null 
          && service2Exception.InnerException.InnerException is FaultException) 
         { 
          FaultException faultException = service2Exception.InnerException.InnerException as FaultException; 

          if (faultException.Detail != null 
           && faultException.Detail.FaultMessage.Equals("SomeValueToCheckAgainst", StringComparison.OrdinalIgnoreCase)) 
          { 
           return someResult; 
          } 
          else 
          { 
           throw service2Exception; 
          } 
         } 
         else 
         { 
          throw service2Exception; 
         } 
        } 

        if (someResult != null) 
        { 
         // perform another action 
         SomeActionInvoker.ExecuteAcitonAgainst(someResult); 
        } 
       } 
      } 
      else if (service1Exception.InnerException != null 
        && service1Exception.InnerException.InnerException != null 
        && service1Exception.InnerException.InnerException is FaultException) 
      { 
       FaultException faultException = service1Exception.InnerException.InnerException as FaultException; 

       if (faultException.Detail != null 
        && faultException.Detail.FaultMessage.Equals("SomeOtherValueToCheckAgainst", StringComparison.OrdinalIgnoreCase)) 
       { 
        return someResult; 
       } 
       else 
       { 
        throw service1Exception; 
       } 
      } 
      else 
      { 
       throw service1Exception; 
      } 
     } 
    } 
} 

回答

1

總而言之,我認爲你會打破一些東西來幫助進入一些輔助方法。例如,你可以提取你的支票,看起來像這樣

if (<exception-instance>.InnerException != null && 
    <exception-instance>.InnerException.InnerException != null && 
    <exception-instance>.InnerException.InnerException is <exception-type>) 

進入一個布爾方法;你通過我的粗略瀏覽至少3次調用這樣的代碼。另外,我建議將第二個頂級案例抽取到錯誤處理方法中;也可能是嵌套的if語句。

0

首先將該方法重構爲多個方法。你有太多的縮進級別了。

之後,考慮一些新方法是否可以提取到其他對象中,並使用IoC風格的方法而不是過程方法。

這是一種高水平的答案,但我累了,沒有精力去真正返工代碼自己:)

1

結賬與Michael Feathers的遺留代碼有效地工作,特別是第22章(我需要更改怪物方法,我無法爲其編寫測試)。那裏有許多偉大的技巧,像你的情況。就個人而言,在這種情況下,我通常最終會從較長方法的各個部分中提取方法,並刪除在整個方法中使用的局部變量;這些幾乎總是麻煩。