Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Common Interface with Different Return Types [Java]

I'm trying to implement the Command pattern in various classes by extending/implementing the Command class which contains a single method public void execute(). However, down the line I noticed I need to implement a number of variations of the pattern to allow it to return different values such as boolean and other custom values. I would like all these classes to inherit/implement a single common interface that requires them to implement the method execute() (and perhaps several other methods) while giving each class the flexibility to add its own return type.

First I thought I could accomplish this with generics but this would not work - as it does not enforce the return type in the sub classes (it would allow for any return type).

Tech, I could create many "Command" classes (such as BooleanCommand + StringCommand + several other such classes with custom return types) but this would mean I need to design each class from scratch as they are not implementing a common interface. In other words, there's no way for me to have BooleanCommand implement the base class Command thereby forcing it to implement the method execute() while allowing it to have it's own return value of boolean. Similarly, I would like the StringCommand class to implement the base class Command (thereby forcing it to implement the method execute() ) while allowing it to have String as a return value.

This might be fine if I had only one method in each class but what if I have several methods and no way to enforce this design?

How can I solve this design issue?

like image 608
Kevin Little Avatar asked May 21 '26 18:05

Kevin Little


2 Answers

You can use generics to allow implementing classes to define the return type:

interface Command<R> {
  R execute();
  R evaluateCommandSuccess();
  R logBefore();
}

interface BooleanCommand extends Command<Boolean> {}
interface StringCommand extends Command<String> {}
interface VoidCommand extends Command<Void> {}

class BooleanCommandImpl implements BooleanCommand {
  @Override public Boolean execute() {
    return true;
  }

  @Override public Boolean evaluateCommandSuccess() {
    return true;
  }

  @Override public Boolean logBefore() {
    return true;
  }
}

class StringCommandImpl implements StringCommand {
  @Override public String execute() {
    return "STRING";
  }

  @Override public String evaluateCommandSuccess() {
    return "STRING";
  }

  @Override public String logBefore() {
    return "STRING";
  }
}

class VoidCommandImpl implements VoidCommand {
  @Override public Void execute() {
    return null;
  }

  @Override public Void evaluateCommandSuccess() {
    return null;
  }

  @Override public Void logBefore() {
    return null;
  }
}

However, as you can see, the XYZCommand interfaces are actually empty; there is no meaningful distinction between XYZCommand and Command<XYZ>: that is pretty much exactly what generics are there for.

like image 120
Jörg W Mittag Avatar answered May 24 '26 12:05

Jörg W Mittag


execute should not return a value. Check the concept of command/query separation. If you really decide to have a return object then you should encapsulate the return object in a class which you can then call getBooleanValue getStringValue