Java回退模式
我试图找到一种很好的方法来实现一个依赖于第三方库类的服务。我还有一个“默认”实现,可以在库不可用或无法提供答案时用作回退Java回退模式,java,design-patterns,strategy-pattern,fallback,proxy-pattern,Java,Design Patterns,Strategy Pattern,Fallback,Proxy Pattern,我试图找到一种很好的方法来实现一个依赖于第三方库类的服务。我还有一个“默认”实现,可以在库不可用或无法提供答案时用作回退 public interface Service { public Object compute1(); public Object compute2(); } public class DefaultService implements Service { @Override public Object compute1() {
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和默认机制几乎相同。此外,如果在服务中添加了另一个方法,则实现看起来几乎相同
是否有一种设计模式可以应用于此处(,),以使代码看起来更好,并使进一步添加的内容更少复制粘贴?Netflix是最好的库之一。我不确定你是否需要这么重的东西。它将为您提供线程池、超时、回退、监视、运行时配置更改、短路等
基本上,它是一个库,用于保护您的代码不受其依赖性故障的影响。在这方面,代理可能会对您有所帮助。下面的示例未经测试,但应能让您了解可以实施哪些措施:
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)
);
}
}
您可以使用方法引用将公共逻辑提取到单独的方法中,如:
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();
}
}
}
公共类ServiceImpl实现服务{
服务defaultService=新的defaultService();
第三方服务第三方服务=新的第三方服务();
@凌驾
公共对象计算机1(){
返回运行(第三方服务::customCompute1,defaultService::compute1);
}
@凌驾
公共对象计算机2(){
返回运行(第三方服务::customCompute2,defaultService::compute2);
}
专用静态T运行(供应商操作、供应商回退){
试一试{
T result=action.get();
返回结果!=null?结果:fallback.get();
}捕获(例外e){
返回fallback.get();
}
}
}
您使用的Java版本是什么?Hystrix看起来很棒!我现在正在评估。它提供了比OP所要求的多得多的东西,但这可能是一件好事……感谢您提到Hystrix。我不知道,但这比我需要的要多,我们有一个关于增加LIB的相当严格的政策。尽管我怀疑如果这些方法带有参数,这个解决方案是否能很好地应用。您必须为至少函数
和双函数
重载运行
,然后您可能需要一个可伸缩性不好的。此外,Service
的每一种新方法都需要在serviceinpl
中进行相应的实现,这也不能很好地扩展,也可能是bug和维护问题的根源。同意@Didier的观点,虽然这是针对这种特定情况的解决方案,但不是一个很好的通用解决方案。方法句柄很酷,但可能不太适合这里。如果fallback.get()
在try
块中抛出异常,它将在catch
块中重复。