Quantcast
Viewing all articles
Browse latest Browse all 38

Answer by Haakon Løtveit for Why use getters and setters/accessors?

EDIT: I answered this question because there are a bunch of people learning programming asking this, and most of the answers are very technically competent, but they're not as easy to understand if you're a newbie. We were all newbies, so I thought I'd try my hand at a more newbie friendly answer.

The two main ones are polymorphism, and validation. Even if it's just a stupid data structure.

Let's say we have this simple class:

public class Bottle {  public int amountOfWaterMl;  public int capacityMl;}

A very simple class that holds how much liquid is in it, and what its capacity is (in milliliters).

What happens when I do:

Bottle bot = new Bottle();bot.amountOfWaterMl = 1500;bot.capacityMl = 1000;

Well, you wouldn't expect that to work, right?You want there to be some kind of sanity check. And worse, what if I never specified the maximum capacity? Oh dear, we have a problem.

But there's another problem too. What if bottles were just one type of container? What if we had several containers, all with capacities and amounts of liquid filled? If we could just make an interface, we could let the rest of our program accept that interface, and bottles, jerrycans and all sorts of stuff would just work interchangably. Wouldn't that be better? Since interfaces demand methods, this is also a good thing.

We'd end up with something like:

public interface LiquidContainer {  public int getAmountMl();  public void setAmountMl(int amountMl);  public int getCapacityMl();}

Great! And now we just change Bottle to this:

public class Bottle implements LiquidContainer {  private int capacityMl;  private int amountFilledMl;  public Bottle(int capacityMl, int amountFilledMl) {    this.capacityMl = capacityMl;    this.amountFilledMl = amountFilledMl;    checkNotOverFlow();  }  public int getAmountMl() {    return amountFilledMl;  }  public void setAmountMl(int amountMl) {     this.amountFilled = amountMl;     checkNotOverFlow();  }  public int getCapacityMl() {    return capacityMl;  }  private void checkNotOverFlow() {    if(amountOfWaterMl > capacityMl) {      throw new BottleOverflowException();    }}

I'll leave the definition of the BottleOverflowException as an exercise to the reader.

Now notice how much more robust this is. We can deal with any type of container in our code now by accepting LiquidContainer instead of Bottle. And how these bottles deal with this sort of stuff can all differ. You can have bottles that write their state to disk when it changes, or bottles that save on SQL databases or GNU knows what else.

And all these can have different ways to handle various whoopsies. The Bottle just checks and if it's overflowing it throws a RuntimeException. But that might be the wrong thing to do.(There is a useful discussion to be had about error handling, but I'm keeping it very simple here on purpose. People in comments will likely point out the flaws of this simplistic approach. ;) )

And yes, it seems like we go from a very simple idea to getting much better answers quickly.

Please note also that you can't change the capacity of a bottle. It's now set in stone. You could do this with an int by declaring it final. But if this was a list, you could empty it, add new things to it, and so on. You can't limit the access to touching the innards.

There's also the third thing that not everyone has addressed: getters and setters use method calls. That means that they look like normal methods everywhere else does. Instead of having weird specific syntax for DTOs and stuff, you have the same thing everywhere.


Viewing all articles
Browse latest Browse all 38

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>