Object creation based on type from parallel hierarchy without instanceof (Java)

  softwareengineering

I have two parallel hierarchies:

  • B and C implement interface A
  • D and E extend the abstract class F

I want to be able to do: F f = createObject(A a)

where createObject should follow the behaviour:

F f createObject(A a){
    if (a instanceof B)
       return new D(a)
    else if (a instanceof C)
       return new E(a)
    else
        throw some error

That is, the creation of F is dependent on the type of A.

I cannot remake the code to remove this parallel hierarchy dependency. I have tried to find some clean solution to this problem that does not involve instanceof, but haven’t been able to.

Any pointers appreciated.

EDIT:

B and C shouldn’t have knowledge about D and E, preferably, as the relationship is that D and E has-an A, and A exists independently of D and E.

5

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.

1

LEAVE A COMMENT