我具有如下定义的语言翻译界面。
public interface TranslationService {
public TranslationResult translate(TranslationRequeset req);
public int maxTranslatableCount();
}
并使用Google,Bing ... etc对该接口进行了多种实现,如下所示:
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”,它在List中定义了故障转移策略,如下所示:
基本上,如果特定服务翻译失败,则会遍历列表。
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填充列表。
最佳答案
首先,建议您制作一个包含所有翻译服务(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
。