2011-12-11 76 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));