Tutorial :Java polymorphic methods



Question:

In Java i have abstract class named Operation and three its subclasses called OperationActivation, OperationPayment and OperationSendEmail.

ADDED FROM COMMENT: Operation* objects are EJB Entity Beans so I can't have business logic inside them.

No I want to create processor class like this:

public class ProcessOperationService {    public void processOperation(Operation operation) {      out.println("process Operation");      process(operation);  }    public void process(OperationActivation operationActivation) {      out.println("process Activation");  }    public void process(OperationPayment operationPayment) {      out.println("process Payment");  }    public void process(OperationSendEmail operationSendEmail) {      out.println("process OperationSendEmail");  }          

}

Processing each operation requires different logic so I want to have three different methods , one for each operation.

Of course this code doesn't compile. Am I missing something or it can't be done that way?


Solution:1

Shouldn't your Operation* objects be doing the work themselves ? So you can write (say)

for (Operation op : ops) {     op.process();  }  

You can encapsulate the logic for each particular operation in its own class, and that way everything related to OperationPayment remains in the OperationPayment class. You don't need a Processor class (and so you don't need to modify a Processor class everytime you add an Operation)

There are more complex patterns to enable objects to mediate wrt. what they need to execute, but I'm not sure you need something that complex at this stage.


Solution:2

You are mixing up overloading and polymorphic method handling. When you overload methods based on the parameter type, that is static polymorphism. Those methods should be called from code that knows at compile-time what the type is. You could possibly do the following, but it wouldn't be clean object-oriented code:

public class ProcessOperationService {    public void processOperation(Operation operation) {      out.println("process Operation");      if (operation instanceof OperationActivation)          process((OperationActivation)operation);      else if (operation instanceof OperationPayment)          process((OperationPayment)operation);      ...  }    public void process(OperationActivation operationActivation) {      out.println("process Activation");  }  ...  }  

It would be much better to let the automatic run-time polymorphism work, by doing as Brian Agnew suggested, and making process be a method of each Operation subtype itself.


Solution:3

Assumption: Operation* objects are subclasses of Operation

Unless the processOperation(Operation) method is performing some common functionality, you could just remove it and expose the process(Operation) methods.

The Command Pattern (JavaWorld Explanation) might be useful, but it's tricky to tell exactly what properties you want from your question.


Solution:4

The problem with the code is that any object that matches one of the process(Operation*) methods will also match the process(Operation) method. As there are 2 methods that can be used, the compiler is warning you of an ambiguous situation.

If you really want/need the code above, I would suggest implementing the process(Operation*) methods, and modify the process(Operation) method so it is called processCommon(Operation). Then, the first thing each process(Operation*) does is call processCommon.

Alternatively, you can code exactly as Avi said, using instanceof comparisons.

Neither is ideal, but it will accomplish what you want.


Solution:5

So you have an abstract class called 'Operation' and it has 3 classes extending it. Not sure if this is what you are after but I'd imagine it be designed something like this:

Operation.java

public abstract class Operation {        public abstract void process();    }  

OperationActivation.java

public class OperationActivation extends Operation {        public void process() {            //Implement OperationActivation specific logic here        }    }  

OperationPayment.java

public class OperationPayment extends Operation {        public void process() {            //Implement OperationPayment specific logic here        }    }  

OperationSendEmail.java

public class OperationSendEmail extends Operation {        public void process() {            //Implement OperationSendEmail spepcific logic here        }    }  

ProcessOperationService.java

public class ProcessOperationService {        public void processOperation(Operation operation) {            out.println("process Operation");          operation.process();        }    }  


Solution:6

Won't the Visitor pattern be of use here ?

The class Operation can declare an "accept" method that takes a Visitor object and the subclasses can have provide the implementation :

public interface IOperationVisitor {     public void visit (OperationActivation visited);     public void visit (OperationPayment visited);     public void visit (OperationSendEmail visited);  }    abstract class Operation {           public void accept(IOperationVisitor visitor)();  }    class OperationActivation extends Operation {      public void accept(IOperationvisitor visitor) {           visitor.visit(this);      }  }  

Similarly define "accept" method for classes OperationPayment and OperationSendEmail ..

Now your class can implement the visitor :

public class ProcessOperationService implements IOperationVisitor  {         public void processOperation(Operation operation) {           operation.accept(this);       }         public void visit (OperationActivation visited) {          // Operation Activation specific implementation       }         public void visit (OperationPayment visited) {          // OperationPayment  specific implementation       }          public void visit ((OperationSendEmail visited) {          // (Operation SendEmail specific implementation         }    }  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »