私の他の答えに加えて、これに対する可能な解決策があります。実装クラスのメソッドに「サービス品質」の注釈を付け、最高の「サービス品質」値で実装に自動的に委任するプロキシを作成します。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
public class DaoProxyDemo {
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface QualityOfService {
int value();
}
interface ProductDao {
String operation1();
String operation2();
}
static class JpaProductDao implements ProductDao {
@QualityOfService(1)
public String operation1() { return "hello from jpa"; }
@QualityOfService(0)
public String operation2() { throw new UnsupportedOperationException(); }
}
static class JdbcProductDao implements ProductDao {
@QualityOfService(0)
public String operation1() { throw new UnsupportedOperationException(); }
@QualityOfService(1)
public String operation2() { return "hello from jdbc"; }
}
static class QosAwareProxyFactory {
public static <T> T createProxy(Class<T> interfaceType, T... implementations) {
class Binding {
private final int qos;
private final T impl;
public Binding(T impl, int qos) {
this.impl = impl;
this.qos = qos;
}
}
final Map<Method, Binding> dispatchMap = new HashMap<Method, Binding>();
try {
for (Method method : interfaceType.getDeclaredMethods()) {
for (T impl : implementations) {
Method implMethod = impl.getClass().getMethod(method.getName(),
method.getParameterTypes());
QualityOfService qos = implMethod.getAnnotation(QualityOfService.class);
int qosValue = qos == null ? 0 : qos.value();
Binding bestSoFar = dispatchMap.get(method);
if (bestSoFar == null || bestSoFar.qos < qosValue) {
dispatchMap.put(method, new Binding(impl, qos.value()));
}
}
}
}
catch (NoSuchMethodException e) {
throw new AssertionError("can never happen");
}
Object proxy = Proxy.newProxyInstance(QosAwareProxyFactory.class.getClassLoader(),
new Class<?>[] {interfaceType}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
T impl = dispatchMap.get(method).impl;
return method.invoke(impl);
}
});
return interfaceType.cast(proxy);
}
}
public static void main(String[] args) {
ProductDao proxy = QosAwareProxyFactory.createProxy(
ProductDao.class, new JpaProductDao(), new JdbcProductDao());
System.out.println(proxy.operation1());
System.out.println(proxy.operation2());
}
}
mainメソッドを実行すると、次のように出力されます。
jpaからこんにちは
jdbcからこんにちは
とにかくサポートされていない操作を実装する必要があるという事実が嫌いな場合は、インターフェイスを分割することを検討できます(他の投稿で提案したように)。