According to Why define a Java object using interface (e.g. Map) rather than implementation (HashMap), I know I should declare the most abstract type possible, so for example:
public interface Fruit{
}
public class Orange extends Fruit{
}
when declaring Orange, I should write "Fruit obj=new Orange();" instead of "Orange obj=new Orange();". However, does the "declare the most abstract type" version has higher coupling actually? Because I think "coupling" of a class is about counting how many other class names appeared in the source file, for example:
Declare the most abstract type : other class names appeared : Fruit, Orange, String (3 classes):
public static void main(String[] args){
Fruit obj=new Orange();
.
.
.
}
Declare the exact type : other class names appeared : Orange, String (2 classes):
public static void main(String[] args){
Orange obj=new Orange();
.
.
.
}
As "declare the most abstract type" contains 3 other class names, so I think the "declare the most abstract type" has higher coupling than the one that declare the exact type (only 2 class names). Is it true? If not, what is the misconception here? How can a class contains the name of other class but not depending on that class?
Note: the question is just about coupling, neither encourage nor discouraging "declaring most abstract type". Also another reason that I think "Fruit obj=new Orange();" has more coupling is, when one day Orange doesn't extends from Fruit anymore:
public class Orange{
}
"Fruit obj=new Orange();" needs changing to "Orange obj=new Orange();" to recompile, while "Orange obj=new Orange();" doesn't need to.
main
function, asmain
is really "glue" code. You'd actually have something like a separate class (or even just a function) that takes in a Fruit, and expresses all of it's logic in terms of Fruit (never mentioning any derived type). That other class is decoupled from the concrete types. Note however, that just having a class extend an interface is not enough to decouple its clients from it. It's the kinds of methods you choose to put on that interface that allow for decoupling (or not).Orange
class is already coupled to the Fruit interface. That is that changes to theFruit
interface will generally require changes to theOrange
class. By depending onOrange
, you've got a transitive dependency on Fruit whether you import it or not.Fruit
and not in any explicit way onOrange
you are so loosely coupled toOrange
that you are independently deployable.