Another option you might consider.
Say you want to reduce the API of some class:
public class LargeApi {
public void doFoo() { ... }
public void doBar() { ... }
public void doBaz() { ... }
...
...
}
Such that clients would only be exposed to say the doFoo method (or any method you'd prefer them to use instead):
public interface ReducedApi {
void doFoo();
}
But in order for instances of the ReducedApi to be used anywhere the LargeApi is expected, you need a way to get back to the LargeApi (preferably without casting):
public interface ReducedApi {
void doFoo();
LargeApiClass asLargeApiClass();
}
An example implementation forcing clients to use your new reduced API might look like the following:
public class ReducedApiImpl
extends LargeApi
implements ReducedApi {
// Don't let them instantiate directly, force them to use the factory method
private ReducedApiImpl() {
}
// Notice, we're returning the ReducedApi interface
public static ReducedApi newInstance() {
return new ReducedApiImpl();
}
@Override
public void doFoo() {
super.doFoo();
}
@Override
public LargeApi asLargeApi() {
return this;
}
}
Now your clients can use your reduced api for the common case, but cast back to the large api when needed:
ReducedApi instance = ReducedApiImpl.newInstance();
instance.doFoo();
callSomeMethodExpectingLargeApi(instance.asLargeApi());