1

During refactoring, I needed to extend existing interface by adding the extra parameter. Now there are many old classes that implement version without parameter, and some new classes that implement the version with parameter:

void exec(int parameter);

vs

void exec();

Ultimately, I need to accept classes implementing both interfaces into the same collection and later process inside the same method. It seems there are two possible approaches for that:

\1. Use instanceof:

int parameter = ...
if (a instanceof NewInterface) 
    ((NewInterface) a).exec(parameter);
else
    ((OldInterface) a).exec();

The benefits of this is that NewInterface and OldInterface can be independent interfaces. When the developer writes a new class, it may be more obvious which methods to override, and overriding the wrong method will result a compile time error.

\2. Use single interface with both methods defined and the parent abstract class that redirects from one method to another:

abstract class Common {
    abstract void exec();
    void exec(int param) { exec(); }
}

This allows to avoid instanceof that is considered bad in some discussions, but now in every new class we must add a weird looking stub:

 // This is not used anymore
 void exec() { };
 // This is a real functionality 
 void exec(int param) { ...

Does not look like the best design ever either, especially taking into consideration the possibility to call this stub by error.

Should I use some third approach, or is this the case when the usage of the instanceof is reasonable?

Audrius Meškauskas
  • 20,936
  • 12
  • 75
  • 93
  • Do you have an access to all the codebase that uses your method? – user3707125 Dec 30 '15 at 11:47
  • Yes, but I would prefer to avoid massive addition of the unused parameter into declaration of many methods that do not need it. Of, if this is really the only right way to go, this would be the possible answer. – Audrius Meškauskas Dec 30 '15 at 11:49
  • 1
    @h22 yet that's the proper thing to do. The interface contract says that exec() takes a parameter, and it's up to the implementation to do something with it, or to ignore it. – JB Nizet Dec 30 '15 at 11:50
  • 2
    Keep both (your second idea) but mark the old method [deprecated](http://stackoverflow.com/questions/9031832/how-to-declare-or-mark-a-java-method-as-deprecated). – OldCurmudgeon Dec 30 '15 at 11:53
  • @OldCurmudgeon it sounds like the old interface isn't truly deprecated though. If a large amount of code never needs to specify this new argument then it sounds like it should be part of the API. h22 Is the existing code an actual interface or is it an abstract class? If it is actually an interface then you could use a default method. – Magnus Dec 30 '15 at 11:58

1 Answers1

2

In case you are using Java 8, you can easily implement it in the interface using a default implementation:

public interface MyInterface {

    void exec();

    default void exec(int param) {
        exec();
    }
}

The exec(int) naturally can be overridden by concrete classes.

Another solution is to have NewInterface extends OldInterface. Then the new classes implement the NewInterface#exec(int) and OldInterface#exec(), the new clients can choose which method to call and the old clients are aware only of OldInterface.

Adam Michalik
  • 9,678
  • 13
  • 71
  • 102