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) 
     ); 
    } 
}