views:

102

answers:

5

Hi

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

+4  A: 

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.

Rob Heiser
Unfortunately, the VO is merely a Data Structure with fields only, no behaviours. I've updated the question to make this clearer.
Marty Pitt
A: 

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.

glowcoder
+1  A: 

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.

akf
+2  A: 

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

Mark Peters
+2  A: 

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) {}
}
Affe