When to use Supertype or Subtype on return method?

7

Suppose I have a method called " meuMetodo() " that returns an Object of type ArrayList<String> , I can make this method declare that it returns more concrete or more abstract types:

  
  • public ArrayList<String> meuMetodo() {...}
  •   
  • public List<String> meuMetodo() {...}
  •   
  • public Collection<String> meuMetodo() {...}
  •   
  • public Object meuMetodo() {...}
  •   
  • Is there a "good practice" convention on which Type to declare as a return for each context ?
  • What are the advantages, disadvantages, and limitations of declaring a more abstract Type? (such as List, Collection, or even Object)
  • What are the advantages, disadvantages, and limitations of declaring a more concrete Type? (in this example, the most concrete would be the ArrayList)

I want a canonical response that takes into account things like:

  • It makes a difference if the method in question will be overwritten by a Subclass in the future (I lose flexibility when extending depending on what I declare as Return Type)?
  • It is important to consider what Customers of this method (the codes that will call it) require the returned Object (for example, the methods they will call on the returned Object)?
  • Is it important to consider for which methods the Returned Object will be sent as an argument?
asked by anonymous 10.05.2017 / 22:08

1 answer

4
  
  • It makes a difference whether the method in question will be overwritten by a Subclass in the future (I lose flexibility by extending depending on   of what I declare as Return Type)?
  •   

Yes. It makes a difference. Imagine you have the supertype:

public interface MySupertype{
  List<String> myMethod()
}

In your subtypes you can return different implementations of List that your code will work on:

class ArraySubType implements MySupertype{
  public List<String> myMethod(){
    return new ArrayList<String>();
  }
}

class LinkedListSubType implements MySupertype{
  public List<String> myMethod(){
    return new LinkedList<String>();
  }
}

Otherwise, if you declare a concrete type in the supertype, you lose flexibility because you are forcing subtypes to use a specific implementation of your return type.

  
  • It is important to consider what the Customers of this method (the codes that will call it) need the returned Object (for example, the methods they will call in the returned Object)?

      
  • It is important to consider for what methods will the Returned Object be sent as an argument?

  •   

In general, yes. If clients of your type / method need to do many casts or get encapsulating the object returned in adapters, this is an indication that the type was poorly designed. On the other hand, it should be taken into account that a multi-method type that caters to many clients may be violating the ISP (principle of segregation of interfaces).

In short: when declaring a method on a type, primarily interfaces and abstract classes, for both parameters and return objects, you must use the type that is as abstract as possible but has the methods required to manipulate the object, or that does not force you to cast. This is called "programming for the interface, not for implementation".

    
20.10.2017 / 13:26