有两种方法:
- 使用适配器模式
- 使用
Proxy
适配器方法将更简单但不太灵活,而该Proxy
方法将更复杂但更灵活。尽管该Proxy
方法更复杂,但这种复杂性都仅限于几个类。
适配器
适配器模式很简单。对于您的示例,它只是一个类,如下所示:
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的Proxy
类
Proxy
是一个本地 Java 类,它是反射库的一部分,可让您创建更通用的反射解决方案。它涉及3个部分:
- 接口(在本例中为
Foo
)
- 这
InvocationHandler
- 创建代理 (
Proxy.newProxyInstance
)
我们已经有了接口,所以我们很好。
这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
和Foo
示例。诚然,这种方法使用反射(Proxy
类使用反射,我们的 也是如此InvocationHandler
),这可能会更慢,但最近 JVM 的改进使反射比以前快得多。