user1884155
user1884155

Reputation: 3736

A java method with both variable return type and variable input arguments

I have an abstract java class "BaseOperation". This class only has a single abstract method:

public abstract T execute()
{
    ...

    return T;
}

Subclasses of BaseOperation must implement this method:

public class GetUsersOperation extends BaseOperation<GetUsersResponse>
{
    ...

    @Override
    public GetUsersResponse execute()
    {

        ...

        return GetUsersResponse;
    }

}

This is a great way to put all common "operation" logic in the BaseOperation class, but still have every concrete subclass's execute() method have a different return type.

Now I need to change this structure to allow the execute() methods to have a variable amount of arguments. For example, one concrete subclass would require:

execute(String, int)

and another would need:

execute(Date, Date, String)

This is tricky, because the execute method is declared in the base class. Simply overloading the execute methods in the base is not ideal. Firstly, the amount of overloads would be huge. Secondly, every subclass will only ever use one of the execute methods, what's the point of all the others?

The (in my opinion) easiest solution would be to declare the execute method with varargs:

execute(Object... arguments)

And then downcast all arguments in the subclasses:

execute(Object... arguments)
{
    String s = (String) arguments[0];
    ...
}

Obviously this has 2 major downsides:

Are there patterns or other solutions that could don't have these disadvantages?

Upvotes: 6

Views: 1629

Answers (2)

NiziL
NiziL

Reputation: 5140

As already said, the common approach for solving your issue is using a bean holding parameters. But here is another solution, based on a builder approach:

public interface BaseOperation<T> {
   public T execute();
}

public class AddOperation implements BaseOperation<Integer> {
   private int a, b;

   public void setA(int arg){
     a = arg ;
     return this;
   }

   public void setB(int arg){
     b = arg;
     return this;
   }

   @Override
   public Integer execute() {
     return a+b ;
   }
}

And then use it like this :

new AddOperation().setA(1).setB(2).execute();

You can mix required and optional parameters in this way:

public class MultipleAddOperation implements BaseOperation<Integer> {
  private int sum ;

  public MultipleAddOperation(int requiredInt){
    sum = requiredInt;
  }

  public void add(int optionalInt){
    sum += optionalInt ;
    return this;
  }

  @Override
  public Integer execute(){
    return sum;
  }
}

And so:

new MultipleAddOperation(5).add(1).add(2).execute();

Upvotes: 3

sp00m
sp00m

Reputation: 48837

You could use a bean holding the parameters:

public interface BaseOperation<T, U> {
    T execute(U input);
}

public class GetUsersOperation implements BaseOperation<GetUsersResponse, UserInput> {

    @Override
    public GetUsersResponse execute(UserInput input) {
        Date date = input.getDate();
        return new GetUsersResponse(date);
    }

}

Your abstract class only has one single abstract method: better use an interface. You can implement several interfaces while you can extend only one class.

Upvotes: 5

Related Questions