10

我试图找到实现依赖于第三方库类服务的一个很好的方式。如果图书馆不可用或无法提供答案,我还有一个“默认”实现作为回退。Java的后备模式

public interface Service { 

    public Object compute1(); 

    public Object compute2(); 
} 

public class DefaultService implements Service { 

    @Override 
    public Object compute1() { 
     // ... 
    } 

    @Override 
    public Object compute2() { 
     // ... 
    } 
} 

实际执行的服务会是这样的:

public class ServiceImpl implements Service { 
    Service defaultService = new DefaultService(); 
    ThirdPartyService thirdPartyService = new ThirdPartyService(); 

    @Override 
    public Object compute1() { 
     try { 
      Object obj = thirdPartyService.customCompute1(); 
      return obj != null ? obj : defaultService.compute1(); 
     } 
     catch (Exception e) { 
      return defaultService.compute1(); 
     } 
    } 

    @Override 
    public Object compute2() { 
     try { 
      Object obj = thirdPartyService.customCompute2(); 
      return obj != null ? obj : defaultService.compute2(); 
     } 
     catch (Exception e) { 
      return defaultService.compute2(); 
     } 
    } 
} 

目前的实现似乎重复的东西,只有在服务的实际调用不同的方式有点,但try/catch和默认机制几乎相同。另外,如果在服务中添加了另一种方法,则实现看起来几乎相同。

是否有可能适用于此的设计模式(proxy,strategy)以使代码看起来更好,并使进一步添加更少的复制粘贴?

+0

什么您使用的是Java版本吗? – Radiodef

回答

3

可以使用方法引用,如提取的共同逻辑放到一个单独的方法:

public class ServiceImpl implements Service { 
    Service defaultService = new DefaultService(); 
    ThirdPartyService thirdPartyService = new ThirdPartyService(); 

    @Override 
    public Object compute1() { 
     return run(thirdPartyService::customCompute1, defaultService::compute1); 
    } 

    @Override 
    public Object compute2() { 
     return run(thirdPartyService::customCompute2, defaultService::compute2); 
    } 

    private static <T> T run(Supplier<T> action, Supplier<T> fallback) { 
     try { 
      T result = action.get(); 
      return result != null ? result : fallback.get(); 
     } catch(Exception e) { 
      return fallback.get(); 
     } 
    } 
} 
+1

我怀疑这个解决方案可以很好地应用,如果方法有参数。你至少必须为'Function'和'BiFunction'重载'run',然后你可能需要['TriFunction'](http://stackoverflow.com/questions/18400210/java-8-where-is java-util-function-or-what-the-alt),但它不能很好地扩展。而且,每个'Service'的新方法都需要在'ServiceImpl'中进行相应的实现,它不能很好地扩展,也可能成为错误和维护问题的根源。 –

+0

同意@Didier,虽然这是针对此特定情况的解决方案,但它不是一个很好的通用解决方案。方法手柄很酷,但可能不太适合这里。 – Guillaume

2

最好的一个库是Netflix'Hystrix。我不确定你是否需要如此沉重的举重。它会给你的线程池,超时,回退,监测,运行时配置的变化,短路等

基本上它是从一个依赖失败捍卫你的代码库。

+0

Hystrix看起来不错!我现在正在评估它。它提供的远远超过OP所要求的,但这可能是件好事... – Guillaume

+0

谢谢你提到Hystrix。虽然没有意识到这一点,但它确实比我需要的要多,而且我们对添加库有相当严格的规定。将检查出来虽然 – user4132657

3

代理也许可以帮助你在这里。下面的例子是未经测试,但应该给你的,你可以放什么地方了一个想法:

public class FallbackService implements InvocationHandler { 

    private final Service primaryService; 
    private final Service fallbackService; 

    private FallbackService(Service primaryService, Service fallbackService) { 
     this.primaryService = primaryService; 
     this.fallbackService = fallbackService; 
    } 

    @Override 
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
     try { 
      Object result = method.invoke(primaryService, args); 
      if (result != null) return result; 
     } catch (Exception ignore) {} 
     return method.invoke(fallbackService, args); 
    } 

    public static Service createFallbackService(Service primaryService, Service fallbackService) { 
     return (Service) Proxy.newProxyInstance(
       Service.class.getClassLoader(), 
       new Class[] { Service.class }, 
       new FallbackService(primaryService, fallbackService) 
     ); 
    } 
}