Search code examples
javaoopinterfacecorrectness

How should i implement an interface in Java? [Code-Correctness]


First of all this is not a question about how to implement an interface in Java, or about an error with interfaces. This is a question about the right way to do it, depending on the situation.

First of all i would like to apologize if this is not the correct "stack" to post this question, please let me know and i'll move it to another one.

Let's begin.

What i'm trying to guess is which is the best way to implement an interface in Java. Let's say we have a class A like:

public Class A {

    public A(){}
    public void fooA() {}
}

And an interface

public interface MyListener {
    public void fooListener();
}

Inside fooA() I'm making use of interface B this way:

...
something.setFooListener(/**Doubts here**/)
....

What should we type inside setFooListener(...)

Options are (As far as i know):

A) Define the behavior inside the setFooListener function:

new MyListener.fooListener() {
    /** Implementation of fooListener() **/
}

Pros:

  • Easy and readable as you're reading the function.

  • You can access directly to FINAL variables defined in fooA().

Cons:

  • If your implementation is long enough it would end up in a lack of readability and a too long function.
  • If you're implementing the interface in a few places on the same class you are going to repeat a lot of code.

B) Create an inner class implementing the interface:

private class MyListenerImplementation implements MyListener {
    private String var1;
    private int var2;

    public MyListenerImplementation() {/** constructor **/}

    public void fooListener() {
        /** Do logic here **/
    }
}

Pros:

  • You can keep a reference to the object MyListenerImplementation.
  • You can define variables, functions and everything as it's an object like any other one.
  • Cleaner code.

Cons:

  • Maybe needs more memory.
  • Maybe creating unnecessary classes

C) Hold a variable with a reference to the interface implementation

private MyListener.FooListener myListenerVar = new MyListener.FooListener() {
    /** Logic goes here **/
};

Pros:

  • I actually can't sees anyone comparing to B, but a lot of cons.

Cons:

  • Not a clean code. Doing this on top of your class would be, at least, a war crime.
  • I don't think it's correct to assign a block of code to a variable.
  • I don't like how this looks ;)

D) The last one i could think of; define a function and inside return the implementation

private MyListener.fooListener createMyListener() {
    return new MyListener.fooListener() {
        /** Logic goes here **/
    }
}

Pros:

  • It's cleaner than C.
  • Reusability

Cons:

  • Almost the same ones as C.
  • I don't think it's correct to return a whole block of code.

To sum up: Which i like the most is "B", but i would like to know what does SO thinks of this.

Thanks in advice.


Solution

  • Option A is not syntaxically correct. Your pros and cons are valid.

    Option B:

    • Maybe needs more memory: no.
    • Maybe creating unnecessary classes: no. Option A also creates a class. It's anonymous, but it's a class, that must be loaded by the ClassLoader like any other class.

    Option C: it's exactly the same as A (anonymous class usage), except you initialize a field with the listener. The rule is the same as for any other variable: reduce its scope as much as possible. If you need a field scope, use this option. If you only need the listener in one method, then use a local variable (option A).

    Option D: once again, it's the same as A, except you return the created listener instead of only using it.

    My recap: you're mixing three orthogonal problems here.

    1. Should I use an anonymous inner class, a named nested class, or a top-level class. This depends on the amount of code contained in the class, and on where you need to use this class: in a single top-level class, or in many top-level classes.
    2. Should I use local variables or instance variables. it's a matter of scope and state, not a matter of interface implementations. Your field or local variable can be initialized with an instance of any kind of your interface implementation
    3. Should you use a factory method returning instances, or should you use new directly. Once again, that has nothing to do with how your interface is implemented. If you want to be loosely coupled, because the factory method might return different implementations of the same interface, use a factory. Otherwise, new is fine.