Marty Pitt
Marty Pitt

Reputation: 29300

Java Polymorphism - Selecting correct method based on subtype

Given the following Class and Service layer signatures:

public class PersonActionRequest {
    PersonVO person
    // ... other fields
}
public class MyServiceLayerClass {

   public void requestAction(PersonActionRequest request)
   {
       PersonVO abstractPerson = request.getPerson();
       // call appropriate executeAction method based on subclass of PersonVO
   }
   private void executeAction(PersonVO person) {}
   private void executeAction(EmployeeVO employee) {}
   private void executeAction(ManagerVO manager) {}
   private void executeAction(UnicornWranglerVO unicornWrangler) {}
}

As discussed here, java will select the best method based on type info at compile time. (Ie., it will always select executeAction(PersonVO person) ).

What's the most appropriate way to select the correct method?

The internet tells me that using instanceof gets me slapped. However, I don't see the appropraite way to select the method without explictly casting abstractPerson to one of the other concrete types.

EDIT: To Clarify - The VO passed in is a simple ValueObject exposed for web clients to instantiate and pass in. By convention it doesn't have methods on it, it's simply a data structure with fields.

For this reason, calling personVO.executeAction() is not an option.

Thanks

Marty

Upvotes: 3

Views: 2522

Answers (5)

Affe
Affe

Reputation: 47994

Your principle obstacle to polymorphism here seems to be a 'dumb-struct' data object + 'manager class' service non-pattern. The "more polymorphic' approach would be for execute() to be a method that the various person implementations override.

Assuming that can't change, the way you do multiple dispatch in Java is with visitor-looking callbacks.

public interface PersonVisitor {
   void executeAction(EmployeeVO employee);
   void executeAction(ManagerVO manager);
   void executeAction(UnicornWranglerVO unicornWrangler);
}
public abstract class PersonVO {
public abstract void accept(PersonVisitor visitor);
}
public class EmployeeVO extends PersonVO {
@Override
public void accept(PersonVisitor visitor) {
  visitor.executeAction(this);
}
}

public class MyServiceLayerClass implements PersonVisitor {

   public void requestAction(PersonActionRequest request)
   {
       PersonVO abstractPerson = request.getPerson();
       abstractPerson.accept(this);
   }

   public void executeAction(EmployeeVO employee) {}
   public void executeAction(ManagerVO manager) {}
   public void executeAction(UnicornWranglerVO unicornWrangler) {}
}

Upvotes: 4

Mark Peters
Mark Peters

Reputation: 81154

The Visitor pattern is often used to overcome Java lacking double-dispatch.

Upvotes: 2

akf
akf

Reputation: 39495

You could change the way you are approaching the design and use a Visitor, passing the executor into the Person and have the person type determine which to call.

Upvotes: 2

corsiKa
corsiKa

Reputation: 82589

I would explicitly cast the abstractPerson. Not only does it ensure the JVM gets the right method, it makes it a hell of a lot easier to read and ensure you know what's going on.

Upvotes: 0

Rob Heiser
Rob Heiser

Reputation: 2862

If executeAction was a method in a base class or interface that was common to PersonVO, EmployeeVO, ManagerVO and UnicornWranglerVO, you could just call abstractPerson.executeAction() instead of having multiple overridden methods.

Upvotes: 5

Related Questions