I struggled with this problem myself. It seems, the only reasonable solution is to use the Visitor Pattern. This avoids instanceof
, and also the need to make instantiation the responsibility of the source type A
. However, the source type hierarchy will need to be updated to support the visitor infrastructure.
First, a Visitor interface:
interface AVisitor<Result> { Result visitB(B object); Result visitC(C object); }
Next, we need to update the A hierarchy to support the visitor:
interface A { <Result> Result accept(AVisitor<Result> visitor); ... } class B implements A { @Override public <Result> Result acccept(AVisitor<Result> visitor) { return visitor.visitB(this); } ... } class C implements A { @Override public <Result> Result acccept(AVisitor<Result> visitor) { return visitor.visitC(this); } ... }
Now, we can implement a visitor that manages object creation from the F hierarchy:
class CreateFFromA implements AVisitor<F> { @Override public F visitB(B b) { return new D(B); } @Override public F visitC(C c) { return new E(c); } }
Finally, we can tie this together in a static helper function:
static F createObjectA(A a) { return a.accept(new CreateFFromA()); }
This is a lot of code and complexity to solve this problem. An instanceof
is far more convenient. So a visitor-based solution is particularly applicable when
- the two class hierarchies must be decoupled at all costs,
- or if there are multiple output type hierarchies, which you want to select at runtime,
- or if you want to be able to statically check that the function handles all known A subclasses.
There is also a substantial restriction: You cannot add new classes to the A hierarchy with either the visitor- or instanceof-based solution. You would have to add the new type to the visitor interface, and then update all visitor implementations to handle that case. If you need this kind of flexibility, you might have to accept some coupling and use a normal A.create()
instance method that subclasses can override.