I have a class from another library that is closed-source, but I want to be able to use an interface for it. The reason being that I don’t want to do instanceof checks or null-checks everywhere, but I also don’t want to extend the existing class.
For example, let’s say I have this code:
public class Example {
// QuietFoo is from another library that I can't change
private static QuietFoo quietFoo;
// LoudFoo is my own code and is meant to replace QuietFoo
private static LoudFoo loudFoo;
public static void main(String[] args) {
handle(foo);
}
private static void handle(Object foo) {
if (foo instanceof QuietFoo)
((QuietFoo) foo).bar();
else if (foo instanceof LoudFoo)
((LoudFoo) foo).bar();
}
}
I can’t change QuietFoo:
public class QuietFoo {
public void bar() {
System.out.println("bar");
}
}
But I can change LoudFoo:
public class LoudFoo {
public void bar() {
System.out.println("BAR!!");
}
}
The problem is, there may be many other implementations of bar in many classes, and there may be more methods than just bar, so not only would my handle method get slow and ugly with lots of instanceof statements, but I would have to write one of these handle methods for each method on QuietFoo and LoudFoo. Extending isn’t a viable solution because it violates the whole is-a contract since LoudFoo is not a QuietFoo.
Basically, given Foo:
public interface Foo {
void bar();
}
How can I make QuietFoo implement Foo without changing its source so I don’t have to do casting and instanceof calls everywhere in my code?
There are two approaches:
ProxyThe adapter approach will be simpler but less flexible, and the
Proxyapproach will be more complex but more flexible. Even though theProxyapproach is more complex, that complexity is all restricted to a couple of classes.Adapter
The adapter pattern is simple. For your example, it would just be one class, like so:
Then to use it:
This is good, but if you have more than one class to make an adapter for, this can be tedious since you’ll need a new adapter for each class you have to wrap.
Java’s
ProxyClassProxyis a native Java class that’s part of the reflection libraries that will allow you to create a more generic, reflective solution. It involves 3 parts:Foo)InvocationHandlerProxy.newProxyInstance)We already have the interface, so we’re fine there.
The
InvocationHandleris where we do our “auto-adapting” via reflection:The important code here is in the
tryblock. This will handle the process of adapting any method calls that are called on the proxy to the innertargetobject. If a method is called on the interface that isn’t supported (non-public, wrong return type, or just flat out doesn’t exist), then we throw anUnsupportedOperationException. If we catch anInvocationTargetException, we rethrow the exception that caused it viaInvocationTargetException.getTargetException. This occurs when the method we called reflectively throws an exception. Java wraps it in a new exception and throws that new exception.Next, we need something to create the adapters:
You could also nest the
AdapterInvocationHandlerclass in theAdapterFactoryclass, if you like, so that everything is self-contained inAdapterFactory.Then to use it:
This approach requires more code than implementing a single adapter, but will be generic enough that it can be used to create auto-adapters for any class and interface pair, not just the
QuietFooandFooexample. Granted, this method uses reflection (theProxyclass uses reflection, as does ourInvocationHandler), which can be slower, but recent improvements in the JVM have made reflection much faster than it used to be.