0

When identifying same code in different classes, how do we decide if we should extract it into an interface or into a superclass ? As Interfaces can't hold any Properties is it that simle to say ("rule of thumb"):

If there is a common property for both classes we extract it into a superclass otherwise into an interface ?

Situation 1: I have 2 seperate classes with 1 identical named method , say calculateCost(). -> Interface

Situation 2: I have 2 seperate classes with 1 identical named method , say calculateCost() and we have id as a String. -> SuperClass

How do we decide to do what ?

Molly
  • 1,887
  • 3
  • 17
  • 34
mcfly soft
  • 11,289
  • 26
  • 98
  • 202
  • "Interfaces can't hold any properties" -> not entirely so, they can have static final values in them. if we're talking about duplicate code, not about duplicate method method signature, then we are most likely talking about the parent class, not about an interface – Stultuske Jan 23 '19 at 07:06
  • @Stultuske the introduction of default methods in interfaces has muddled that distinction – Erwin Bolwidt Jan 23 '19 at 07:08
  • @ErwinBolwidt which is why I said "most likely". even though default methods make the disctinction a wee bit different, if there happens to be a parent class with a method with the same signature, though, the default method will be ignored in favor of that method. So, if there is any chance there is, or ever will be, a parent class to provide an implementation, I would opt for that. – Stultuske Jan 23 '19 at 07:15
  • 2
    Possible duplicate of [Interface with default methods vs Abstract class in Java 8](https://stackoverflow.com/questions/19998454/interface-with-default-methods-vs-abstract-class-in-java-8) – jaco0646 Jan 23 '19 at 15:46

2 Answers2

0

Even though this is mostly opinion, there is one thing you should remember:

public class Child extends Parent implements MyInterface {
  public static void main(String[] args) {
    Child c = new Child();
    c.logSomething("toLog");
  }
}

Let's check this for all possible scenario's: First, there is such a method in the Parent class, not in the interface.

public class Parent {
  public void logSomething(String toLog) {
    System.out.println("Parent: " + toLog);
  }
}

public interface MyInterface {

}

Obviously, the result will be:

Parent: toLog

Second scenario, the code is provided by the interface, not the class.

public class Parent {

}

public interface MyInterface {
  default void logSomething(String toLog) {
    System.out.println("Interface: " + toLog);
  }
}

Here, it will also work, and the result will be:

Interface: toLog

But, when both provide it:

public class Parent {

  public void logSomething(String toLog) {
     System.out.println("Parent: " + toLog);
  }

}

public interface MyInterface {
  default void logSomething(String toLog) {
    System.out.println("Interface: " + toLog);
  }
}

The result will be:

Parent: toLog

Are you 100% sure there is no parent class, and there never will be one (that might provide (or inherit itself)) an implementationf or that method signature? Then it's a free choice.

On the other hand, if you opt for a default method, and someone does decide to add a parent class, that might lead to some stressful debugging.

Stultuske
  • 9,296
  • 1
  • 25
  • 37
0

The suggested thread by @jaco0646 explains the difference between superclasses and interfaces very well.

As for a "rule of thumb", I usually ask my self: is the relationship between the abstractions a...

  • "behaves like" relationship? -> interface
  • "is a" relationship? -> superclass

Thinking in these terms makes the codebase easier to understand, more intuitive to navigate, read and maintain.

Also keep in mind that you can only inherit from one superclass. Inheritance is a strong contract that creates highly coupled relationships, therefore it should only be used when the situation calls for it (this is in my opinion, when the conceptual model fits nicely with the "is a" kind of relationship).

Aldana
  • 383
  • 1
  • 9