2013-10-23 22 views
1

我有一個如下定義的語言翻譯界面。春天:移動stradegy代碼或保留在XML文件?

public interface TranslationService { 
    public TranslationResult translate(TranslationRequeset req); 
    public int maxTranslatableCount(); 
} 

並通過如下使用谷歌,必應...等有接口的幾種實現方式:

public class BingTranslationServiceImpl implements TranslationService { 
public TranslationResult translate(TranslationRequeset req){} 
public int maxTranslatableCount(){return 10000;} 
} 


public class GoogleTranslationServiceImpl implements TranslationService { 
    public TranslationResult translate(TranslationRequeset req){} 
    public int maxTranslatableCount(){return 2000;} 
} 

public class FooTranslationServiceImpl implements TranslationService { 
    public TranslationResult translate(TranslationRequeset req){} 
    public int maxTranslatableCount(){return 50000;} 
} 

然後在我們的客戶端代碼,我們必須執行,如果一個特定的故障轉移翻譯服務失敗。

爲了實現這一目標,我介紹了一個「TranslationProxy」在列表定義故障切換策略如下:

基本上這個迭代通過列表,如果一個特定的服務未能轉化。

public class TranslationProxy implements TranslationService { 
    private List<TranslationService> services; 

    TranslationResult translate(TranslationRequeset req) { 
     // 
    } 
    public List<TranslationBusinessLogic> getServices() { 
     return services; 
    } 
    public void setServices(List<TranslationBusinessLogic> services) { 
     this.services = services; 
    } 

} 

然後在我的Spring配置我定義的服務實現如下:

<bean id="bing" class="com.mycompany.prj.BingTranslationServiceImpl" scope="singleton"/> 
<bean id="google" class="com.mycompany.prj.GoogleTranslationServiceImpl" scope="singleton"/> 
<bean id="foo" class="com.mycompany.prj.FooTranslationServiceImpl" scope="singleton"/> 

併爲每個故障切換策略,我定義 「TranslationProxy」 豆如下:

<bean id="translationProxy_Bing_Google" class="com.mycompany.prj.TranslationProxy" scope="singleton"> 
     <property name="services"> 
      <list> 
       <ref bean="bing"/> 
       <ref bean="google"/> 
      </list> 
     </property> 
    </bean> 

    <bean id="translationProxy_Foo_Bing_Google" class="com.mycompany.prj.TranslationProxy" scope="singleton"> 
     <property name="services"> 
      <list> 
       <ref bean="foo"/> 
       <ref bean="bing"/> 
      <ref bean="google"/> 
      </list> 
     </property> 
    </bean> 

在客戶端代碼:

class SomeBusinessLogic { 
    @Autowired 
    @Qualified("translationProxy_Bing_Google") 
    private TranslationService translationService; 

    public void some_method_which_uses_translation() { 
    result = translationService(request); 
    } 

} 

另一個地方:

class SomeAnotherBusinessLogic { 
    @Autowired 
    @Qualified("translationProxy_Foo_Bing_Google") 
    private TranslationService translationService; 

    public void some_method_which_uses_translation_with_different_failover_stradegy() { 
    result = translationService(request); 
    } 

} 

這不是實現這個故障切換stradegy最乾淨的方式是什麼?

我被要求將故障轉移條件轉移到客戶端代碼中。

喜歡的東西以下(在彈簧是不可能的):

class SomeBusinessLogic { 
    @Autowired 
    @SomeAnnotationDefiningTheStradegy("bing","google") 
    private TranslationService translationService; 

    public void some_method_which_uses_translation() { 
    result = translationService(request); 
    } 

這裏的「SomeAnnotationDefiningTheStradegy」是一個註釋這將填補與所述參數定義的豆的列表。

回答

1

從功能上來說,我看不出您的兩個選項有什麼區別。您明確使用的是ServiceCoordinator,您稱之爲TranslationProxy來處理您的TranslationService實現列表,最終使用Strategy Pattern。它看起來有點乏味,要定義你的代理的多個排列組合,它們完全不同,因爲他們引用了TranslationService實現的列表,但正如你所指出的,你需要一些自定義的Spring魔法來實現第二個選項,除非你要注入所需的服務(在您的示例中爲「bing」和「google」)以及代理到您的業務邏輯bean中,然後將這些服務以參數List傳遞給代理(而不是在配置時將它們注入代理)。這意味着,你仍然會使用「策略模式」,但是您的策略容器現在只是在運行時傳遞的列表,而不是在配置期間在代理中引用。這裏可能會有更優雅的東西,但實際上這聽起來像你會「移動污垢」這樣說。我會再考慮一下。這是一個有趣的問題。 =)

2

首先,我建議你製作一個包含所有翻譯服務的枚舉(enum TranslationServiceProvider {BING, GOOGLE, FOO})並用它來代替字符串。向TranslationService接口返回提供者(TranslationServiceProvider getProvider())添加一個方法也很有用。

在我看來,最直接的選擇是會是這樣的:

class SomeAnotherBusinessLogic { 

    private TranslationService translationService; 

    @Autowired 
    public void setTranslationService(TranslationDecider translationDecider) { 
     translationService = translationDecider.getProxyFor(
      TranslationServiceProvider.BING, TranslationServiceProvider.FOO); 
    } 

    ... 
} 

@Component 
public class TranslationDeciderImpl implements TranslationDecider { 

    @Autowired 
    private List<TranslationService> translationServices; 

    public TranslationProxy getProxyFor(TranslationServiceProvider ... providers) { 
     List<TranslationService> services = // translationServices filtered using getProvider() 
     return new TranslationProxy(services); 
    } 

} 

TranslationProxy不是由Spring管理,但可能是沒有必要的。如果是,則需要TranslationProxyFactory

+0

+1另一個不錯的選擇。再一次,以上所有內容在執行過程中幾乎完全相同。這取決於OP如何構建它。 – MattSenter

+0

添加第四個簡單翻譯服務時,爲不同(簡單)翻譯服務創建枚舉會導致代碼更改。問題在於爲故障轉移策略更改代碼,而不是單個翻譯服務。 –