1

我有一个如下定义的语言翻译界面。

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 定义如下:

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

}

TranslationProxy不是由 Spring 管理的,但可能不是必需的。如果是,TranslationProxyFactory则需要 a。

于 2013-10-28T15:26:50.993 回答
1

从功能上讲,我认为您的两个选项之间没有区别。本质上,您显然在使用ServiceCoordinatoraTranslationProxy来处理您的TranslationService实现列表,最终使用了Strategy Pattern。定义代理的多个排列看起来确实有点乏味,这些排列仅因TranslationService它们引用的实现列表而异,但是正如您所指出的,除非您要注入所需的服务,否则您将需要一些自定义的 Spring 魔法来实现您的第二个选项(在您的示例中为“bing”和“google”)以及代理到您的业务逻辑 bean,然后将这些服务传递给List代理的参数(而不是在配置时将它们注入代理。)从这个意义上说,您仍然使用“策略模式”,但您的策略容器现在只是在运行时传递的列表,而不是在您的配置期间的代理。这里可能有一些更优雅的东西,但实际上听起来你可以说是在“移动污垢”。我会再考虑一下。这是一个有趣的问题。=)

于 2013-10-28T03:31:30.890 回答