1

以下に定義する言語翻訳用のインターフェースがあります。

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

また、次のように、Google、Bing ...などを使用したインターフェイスの実装がいくつかあります。

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 を次のように定義します。

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

}

これは、このフェールオーバー戦略を実装する最もクリーンな方法ではありませんか?

フェールオーバー戦略をクライアント コードに移すように依頼されました。

次のようなもの(春には不可能です):

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

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

ここで、「SomeAnnotationDefiningTheStradegy」は、引数で定義された Bean でリストを埋める注釈です。

4

2 に答える 2

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

}

TranslationProxySpring によって管理されていませんが、おそらく必要ありません。その場合は aTranslationProxyFactoryが必要です。

于 2013-10-28T15:26:50.993 に答える
1

機能的には、2 つのオプションに違いはありません。ServiceCoordinator基本的に、 aを呼び出して実装TranslationProxyのリストをTranslationService処理し、最終的にStrategy Patternを使用していることは明らかです。参照する実装のリストだけが異なるプロキシの複数の順列を定義するのは少し面倒に見えますTranslationServiceが、あなたが示したように、必要なサービスを注入しない限り、2 番目のオプションを実現するにはカスタム Spring マジックが必要です。 (あなたの例では「bing」と「google」)プロキシとともにビジネスロジックBeanに入れ、それらのサービスをListその意味では、「戦略パターン」を引き続き使用しますが、戦略コンテナーは、実行時に参照されるのではなく、実行時に渡される単なるリストになります。構成中のプロキシ。ここにはもっとエレガントなものがあるかもしれませんが、実際には、いわば「汚れを動かす」ように聞こえます。もう少し考えてみます。これは楽しい問題です。=)

于 2013-10-28T03:31:30.890 に答える