7

For example:

URL blogFeedUrl = new URL("http://manishmaharzan.com.np/getJSON/json.json");
HttpURLConnection connection = (HttpURLConnection) blogFeedUrl.openConnection();
connection.connect();
InputStream inputStream = connection.getInputStream();
Reader reader = new InputStreamReader(inputStream);
int contentLength = connection.getContentLength();
char[] charArray = new char[contentLength];
reader.read(charArray);
String responseData = new String(charArray);

Here we could have created InputStreamReader instead for parent class Reader:

InputStreamReader reader = new InputStreamReader(inputStream);

Or for another example when creating a SQLiteOpenHelper in an activity:

public class Helper extends SQLiteOpenHelper
{
    …
}

public class DrinkActivity extends Activity
{
   protected void onCreate(…) { … }
   SQLiteOpenHelper helper = new Helper(this);
   …
}

Instead of referencing the base class SQLiteOpenHelper here, why not create

Helper helper = new Helper(this);

after all Helper extends SQLiteOpenHelper.

What is the benefit of coding it this way?

  • Reader cannot be instantiated because it's abstract. – Tulains Córdova Mar 28 '16 at 17:48
9

In layman's words:

By declaring the variable with the superclass type (i.e. Reader or SQLiteOpenHelper) you assure that the code that uses that object will work even if you instatiate it to a different kind of Reader or a different kind of SQLiteOpenHelper as long as they are a subclass of Reader or SQLiteOpenHelper respectively. The code should work fine if you pass it a FileReader or a StringReader.

A real life comparison:

When you learn to drive a manual transmission car, you can drive almost any manual transmission car. Imagine how bad it would be if you had to learn to drive every different model of car you encounter.

What you learned is abstract: shifting gears, using the clutch, etc. It applies to lots of car models as long as they respect that way of working. Being abstract and not depending on any particular car model, your driving skills are more useful.

That's not coincidence. Car makers design their cars to comply with what you expect. Every car is different, some have bells and wistles, but by having a clutch, a steering wheel (instead of a joystick), and by having the clutch, brake and gas pedal in the locations you expect, they leverage the fact that most users learned to drive an abstract "manual transmission car". Some cars have assisted steering, others have ABS brakes but those details are transparent to you. You don't have to know about them in order to use the general skills of how to drive.

When you write code depending on Reader, you are teaching your code tricks that are more useful. It will be able to handle any Reader. If you code for a specific implementation, like InputStreamReader, your code is less useful, because you most surely will end up calling methods that only exist in that specific implementation. If that's what you need to do, so be it, but if that's not so, by programming to the more general (abstract) class (declaring your variables as that) your code will benefit and it will be more flexible.

8

Mostly this is due to the Interface Segregation Principle. You want your client code to depend on as small an interface as necessary, and that means the most abstract class. This isolates your code here from changes in the derived classes that you don't care about.

Another benefit is if you make a mistake and instantiate a class that doesn't actually implement the interface, or perhaps that code is changed later so that it no longer implements the interface, the compiler error will point you to the line where it is declared, rather than later down where it makes less sense.

It's all about adopting style choices that minimize the possibility of introducing errors, and make it easy to find those errors when you do make them.

  • thanks for the answer but sorry to say that i didn't understand a bit what you just said may be i just need to dig more deep into OOP , thanks for the effort tho... – mhrzn Mar 28 '16 at 11:53
  • @mhrzn the general idea behind ISP is to rely on high-level interfaces containing the minimum amount of functionality. If you rely on lower-level interfaces or concrete implementations, your code is more brittle and you increase the risk of bugs. Karl's answer goes into more detail but that is the core of the principle. – user22815 Mar 28 '16 at 19:41
1

To provide a less "academic" answer: it limits the scope which is always good. It sends a message to the next programmer who will look at the code that the purpose of the reader object is to get your data and the technicalities (implementation details) of the derived class do not matter. It is polymorphism making it easier to follow the basic logic of the code.

Seeing the child class instance being assigned to a parent class variable suddenly makes thing easier because you know you won't have to consider any of the added functionality of the child object. It filters out the noise for you and helps you focus on what is relevant.

1

I like the List example of this concept.

Let's say you create a method that does some processing and internally uses an ArrayList which is a specific implementation of the List interface. Then you return a reference to the ArrayList and all is well.

Then a month later you change the method implementation because it turns out ArrayList is holding you back. You want to add an element to the middle of the list and ArrayList is too slow. A LinkedList is a better data structure for this. So now you have to change your return type to LinkedList and the user of your method has to change their calling code too.

If you had just returned a reference to the List interface, you could change your implementation without changing your API.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.