2011-12-11 81 views
3

我正在開發一種解決方案,它將連接到各種服務器以讀取數據並執行操作。有許多變量使得可靠的通信複雜化,例如防火牆,停止/失敗的服務,認證差異以及各種軟件配置。我可以使用一些方法來解決這些問題,但在執行時不知道哪些方法會證明是成功的。多次實施嘗試

我的目標是創建一個可用於執行操作的接口和實現。第一個方法調用將用於大多數設備之後的最快實現,其次是可以處理前面列出問題的其他調用。

在一個完美的世界中,將編寫這個過程來快速確定哪個方法會成功,但是在我的測試中,只需要處理很多時間就像捕捉異常一樣。雖然性能始終是一個考慮因素,但最終,任務成功完成更爲重要。

下面是我創建的一個示例,它演示了遍歷實現列表的最壞情況場景。雖然這適用於一種方法,但在20個或更多不同操作中使用時,它不遵循DRY原則。一個可能的解決方案是Unity和攔截,但我發現調用處理程序中的invoke方法使用已解析的實現,而不是可能的實現列表。除非我錯過了一些東西,否則這似乎不是一種選擇。另外,我將需要遵循這個模式的幾個接口,所以創建一個可以遍歷實現列表的通用處理程序會很好。

有關如何完成此任務的任何建議,將不勝感激!

接口

public interface IProcess 
{ 
    int ProcessItem(string workType); 
} 

實現

public class ProcessImplementation1 : IProcess 
{ 
    public int ProcessItem(string workType) 
    { 
     throw new TimeoutException("Took too long"); 
    } 
} 

public class ProcessImplementation2 : IProcess 
{ 
    public int ProcessItem(string workType) 
    { 
     throw new Exception("Unexpected issue"); 
    } 
} 

public class ProcessImplementation3 : IProcess 
{ 
    public int ProcessItem(string workType) 
    { 
     return 123; 
    } 
} 

特別實施通過其他實現循環,直到一個成功,無一例外

public class ProcessImplementation : IProcess 
{ 
    public int ProcessItem(string workType) 
    { 
     List<IProcess> Implementations = new List<IProcess>(); 
     Implementations.Add(new ProcessImplementation1()); 
     Implementations.Add(new ProcessImplementation2()); 
     Implementations.Add(new ProcessImplementation3()); 
     int ProcessId = -1; 
     foreach (IProcess CurrentImplementation in Implementations) 
     { 
      Console.WriteLine("Attempt using {0} with workType '{1}'...", 
       CurrentImplementation.GetType().Name, workType); 
      try 
      { 
       ProcessId = CurrentImplementation.ProcessItem(workType); 
       break; 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine(" Failed: {0} - {1}.", 
        ex.GetType(), ex.Message); 
      } 
      Console.WriteLine(); 

      if (ProcessId > -1) 
      { 
       Console.WriteLine(" Success: ProcessId {0}.", ProcessId); 
      } 
      else 
      { 
       Console.WriteLine("Failed!"); 
      } 
      return ProcessId; 
     } 
    } 
} 
+0

我要建議的複合模式,當仔細閱讀我意識到你會已經實施了它。 – TrueWill

+0

@Maxim - 你爲什麼要刪除你的責任鏈模式答案?我打算贊成這個! – TrueWill

回答

0

你可以在第二個界面使用TryParse模式:

public interface IProcess 
{ 
    int ProcessItem(string workType); 
} 

internal interface ITryProcess 
{ 
    bool TryProcessItem(string workType, out int result); 
} 

public class ProcessImplementation1 : ITryProcess 
{ 
    public bool TryProcessItem(string workType, out int result) 
    { 
     result = -1; 
     return false; 
    } 
} 

public class ProcessImplementation : IProcess 
{ 
    public int ProcessItem(string workType) 
    { 
     var implementations = new List<ITryProcess>(); 
     implementations.Add(new ProcessImplementation1()); 
     // ... 
     int processId = -1; 
     foreach (ITryProcess implementation in implementations) 
     { 
      if (implementation.TryProcessItem(workType, out processId)) 
      { 
       break; 
      } 
     } 
     if (processId < 0) 
     { 
      throw new InvalidOperationException("Unable to process."); 
     } 
     return processId; 
    } 
} 
+1

我最終走上了這條路。雖然這不是最乾的解決方案,但它確實解決了我在整個解決方案中處理大量異常的問題。 – Robert

1

您可以實現處理的操作,你傳遞所進行的處理單個項目的方法的通用擴展方法:

public static int ProcessItems<T>(this IEnumerable<T> items, Func<T, int> processMethod) 
{ 
    foreach (var item in items) 
    { 
     try 
     { 
      return processMethod(item); 
     } 
     catch(Exception) {} 
    } 
    return -1; 
} 

現在您已將因素的實際類型和您用於處理的方法分解了出來。唯一的「固定」是通用方法的結果類型,它是一個整數。

您當前例如,你可以這樣調用它,那麼:

List<IProcess> implementations = ...; 
int processResult = items.ProcessItems(x => x.ProcessItem(workType)); 
0

這裏的類似,如果你想要的東西很簡單,「一般由@BrokenGlass中創建一個解決方案。「

public void TryAllImplementations<TService>(
    IEnumerable<TService> services, 
    Action<TService> operation, 
    Action<Exception> exceptionHandler = null) 
{ 
    int dummy = 0; 
    TryAllImplementations(
     services, 
     svc => { operation(svc); return dummy; }, 
     exceptionHandler); 
} 

public TReturn TryAllImplementations<TService, TReturn>(
    IEnumerable<TService> services, 
    Func<TService, TReturn> operation, 
    Action<Exception> exceptionHandler = null) 
{ 
    foreach (var svc in services) 
    { 
     try 
     { 
      return operation(svc); 
     } 
     catch (Exception ex) 
     { 
      if (exceptionHandler != null) 
       exceptionHandler(ex); 
     } 
    } 
    throw new ProgramException("All implementations have failed."); 
} 

因爲我看到一個統一的標籤,你可以使用你的服務接口來獲取所有實現,結合本代碼的容器上使用ResolveAll<TService>(),你可以不喜歡的擴展方法上IUnityContainer

public static class UnityContainerExtensions 
{ 
    public static void TryAllImplementations<TService>(
     this IUnityContainer container, 
     Action<TService> operation, 
     Action<Exception> exceptionHandler = null) 
    { 
     int dummy = 0; 
     container.TryAllImplementations<TService, int>(
      svc => { operation(svc); return dummy; }, 
      exceptionHandler); 
    } 

    public static TReturn TryAllImplementations<TService, TReturn>(
     this IUnityContainer container, 
     Func<TService, TReturn> operation, 
     Action<Exception> exceptionHandler = null) 
    { 
     foreach (var svc in container.ResolveAll<TService>()) 
     { 
      try 
      { 
       return operation(svc); 
      } 
      catch (Exception ex) 
      { 
       if (exceptionHandler != null) 
        exceptionHandler(ex); 
      } 
     } 
     throw new ProgramException("All implementations have failed."); 
    } 
} 

這裏是如何使用它可以工作:

IUnityContainer container; 

// ... 

container.RegisterType<IProcess, ProcessImplementation1>(); 
container.RegisterType<IProcess, ProcessImplementation2>(); 
container.RegisterType<IProcess, ProcessImplementation3>(); 

// ... 

container.TryAllImplementations(
    (IProcess svc) => svc.ProcessItem(workType), 
    ex => Console.WriteLine(
     " Failed: {0} - {1}.", 
     ex.GetType(), 
     ex.Message));