Design suggestion: Changing the class behaviour

60 views Asked by At

Below I am trying to explain the problem with an example.

We have a Caller.java

Caller.java : which calls the series of Actors to perform certain steps in sequence.

Actor.java : Abstract class containing action() method

ActorOne.java : Implements the action() method

ActorTwo.java : Implements the action() method

ActorThree.java : Implements the action() method

At runtime, based on a task to accomplish, a collection of classes is prepared inside Caller.java and instantiated using the Reflection.

Actor.java: callActions(){
Class[] classes = [ActorOne.class, ActorTwo.class]

for(Class clazz : classes){
   Actor actor = (Actor) clazz.newInstance();
   actor.action(); 
}
}

In certain situation, which I know runtime inside the callActions.java, I need to inform the ActorTwo to peform the action method differently.

My solution is to pass that flag to the ActorTwo object using Reflection API and inside the action() method put if/else to perform the flag specific action.

Is there a better way to design the solution, so that I can avoid the if/else within the ActorTwo.action() method?

Best Regards

3

There are 3 answers

0
Mshnik On BEST ANSWER

Another option is to make the action() method take an array of arguments (like main(...) does). That way ActorTwo could check the arguments to see if its in the special case, whereas the other Actors could just ignore the input.

public abstract class Actor{
    public abstract void action(String[] args);
}

public class Actor2 extends Actor{

    public void action(String[] args){
        if(args != null && args.length > 0 && args[0].equals("SPECIAL_CASE"){
            //Do special case things
        } else {
            //Do regular case things
        }
    }
}

This formation gives you the most flexibility going forward with adding extra cases to any actors.

0
zookastos On

Use polymorphism. Define one more method in your ActorTwo.java called action(flag), and then implement the new behavior in this method. When you do not want to pass flag, normal action() should be called. When you want to pass flag, on runtime, you should call action(flag).

A word of advise, try to avoid reflection if possible. It slows down the execution. If it is not possible for your code to avoid reflection, that is fine.

3
JP Moresmau On

You could have two methods on your interface. ActorOne and ActorThree would delegate the implementation of one method to the other (maybe an abstract super class would do that). ActorTwo would do something different.

You could have another interface with the different method, and have ActorTwo implement it, and at runtime check if your object supports it

 if(inSpecialCase && actor instanceof Actor2) {
   ((Actor2)actor).specialMethod()

Eclipse works like the second suggestion a lot, to preserve extensibility and compatibility (new interfaces are created over time and the behavior adapts depending on what level the code supports).