有两种方法:
- 使用适配器模式
- Using Proxy http://docs.oracle.com/javase/6/docs/api/java/lang/reflect/Proxy.html
适配器方法会更简单但灵活性较差,并且Proxy
方法将更加复杂但更加灵活。尽管Proxy
方法更复杂,这种复杂性仅限于几个类。
Adapter
The 适配器模式 http://www.oodesign.com/adapter-pattern.html很简单。对于您的示例,它只是一个类,如下所示:
public class QuietFooAdapter implements Foo {
private QuietFoo quietFoo;
public QuietFooAdapter(QuietFoo quietFoo) {
this.quietFoo = quietFoo;
}
public void bar() {
quietFoo.bar();
}
}
然后使用它:
Foo foo = new QuietFooAdapter(new QuietFoo());
foo.bar();
这很好,但如果您有多个类需要为其创建适配器,这可能会很乏味,因为您需要为每个必须包装的类提供一个新的适配器。
Java's Proxy
Class
Proxy
是一个本机 Java 类,它是反射库的一部分,可让您创建更通用的反射解决方案。它涉及3个部分:
- 接口(在本例中,
Foo
)
- The InvocationHandler http://docs.oracle.com/javase/6/docs/api/java/lang/reflect/InvocationHandler.html
- 创建代理(Proxy.newProxyInstance http://docs.oracle.com/javase/6/docs/api/java/lang/reflect/Proxy.html#newProxyInstance%28java.lang.ClassLoader,%20java.lang.Class%5B%5D,%20java.lang.reflect.InvocationHandler%29)
我们已经有了界面,所以一切都很好。
The InvocationHandler
是我们通过反射进行“自动适应”的地方:
public class AdapterInvocationHandler implements InvocationHandler {
private Object target;
private Class<?> targetClass;
public AdapterInvocationHandler(Object target) {
this.target = target;
targetClass = target.getClass();
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
Method targetMethod = targetClass.getMethod(method.getName(), method.getParameterTypes());
if (!method.getReturnType().isAssignableFrom(targetMethod.getReturnType()))
throw new UnsupportedOperationException("Target (" + target.getClass().getName() + ") does not support: " + method.toGenericString());
return targetMethod.invoke(target, args);
} catch (NoSuchMethodException ex) {
throw new UnsupportedOperationException("Target (" + target.getClass().getName() + ") does not support: " + method.toGenericString());
} catch (IllegalAccessException ex) {
throw new UnsupportedOperationException("Target (" + target.getClass().getName() + ") does not declare method to be public: " + method.toGenericString());
} catch (InvocationTargetException ex) {
// May throw a NullPointerException if there is no target exception
throw ex.getTargetException();
}
}
}
这里重要的代码位于try
堵塞。这将处理将代理上调用的任何方法调用调整为内部的过程。target
目的。如果在不支持的接口上调用方法(非public
,错误的返回类型,或者根本不存在),然后我们抛出一个UnsupportedOperationException
。如果我们抓住一个InvocationTargetException
,我们重新抛出导致它的异常InvocationTargetException.getTargetException
。当我们反射调用的方法抛出异常时,就会发生这种情况。 Java 将其包装在一个新的异常中并抛出该新的异常。
接下来,我们需要一些东西来创建适配器:
public class AdapterFactory {
public static <T> T createAdapter(Object target, Class<T> interfaceClass) {
if (!interfaceClass.isInterface())
throw new IllegalArgumentException("Must be an interface: " + interfaceClass.getName());
return (T) Proxy.newProxyInstance(null, new Class<?>[] { interfaceClass }, new AdapterInvocationHandler(target));
}
}
你也可以嵌套AdapterInvocationHandler
类在AdapterFactory
类,如果你愿意的话,这样一切都是独立的AdapterFactory
.
然后使用它:
Foo foo = AdapterFactory.createAdapter(new QuietFoo(), Foo.class);
foo.bar();
这种方法比实现单个适配器需要更多的代码,但足够通用,可以用于为任何类和接口对创建自动适配器,而不仅仅是QuietFoo
and Foo
例子。当然,此方法使用反射(Proxy
类使用反射,我们的InvocationHandler
), 哪个can速度会更慢,但最近 JVM 的改进使得反射比以前快得多。