22

We always say that data will be encapsulated if we simply define variables private and define getters setters to access those variables. My question is if we can access the variables (data) though via getters and setters, how come data is hidden or safe?

I googled a lot for an explanation, but I found nothing. Every one just said in their blogs and posts that it is a data hiding technique, but it has not been explained/elaborated.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Just_another_developer
  • 5,737
  • 12
  • 50
  • 83

9 Answers9

61

Encapsulation is more than just defining accessor and mutator methods for a class. It is a broader concept of object-oriented programming that consists in minimizing the interdependence between classes and it is typically implemented through information hiding.

The beauty of encapsulation is the power of changing things without affecting its users.

In an object-oriented programming language like Java, you achieve encapsulation by hiding details using the accessibility modifiers (public, protected, private, plus no modifier which implies package-private). With these levels of accessibility, you control the level of encapsulation, the less restrictive the level, the more expensive change is when it happens and the more coupled the class is with other dependent classes (i.e. user classes and subclasses).

Therefore, the goal is not to hide the data itself, but the implementation details on how this data is manipulated.

The idea is to provide a public interface through which you gain access to this data. You can later change the internal representation of the data without compromising the public interface of the class. On the contrary, by exposing the data itself, you compromise encapsulation, and therefore, the capacity of changing the way you manipulate the data without affecting its users. You create a dependency on the data itself, and not on the public interface of the class. You would be creating a perfect cocktail for trouble when "change" finally finds you.

There are several reasons why you might want to encapsulate access to your fields. Joshua Bloch in his book Effective Java, in Item 14: Minimize the accessibility of classes and members, mentions several compelling reasons, which I quote here:

  • You can limit the values that can be stored in a field (i.e. gender must be F or M).
  • You can take actions when the field is modified (trigger event, validate, etc.).
  • You can provide thread safety by synchronizing the method.
  • You can switch to a new data representation (i.e. calculated fields, different data types)

However, encapsulation is more than hiding fields. In Java you can hide entire classes, by this, hiding the implementation details of an entire API. Think, for example, in the method Arrays.asList(). It returns a List implementation, but you do not care which implementation, as long as it satisfies the List interface, right?. The implementation can be changed in the future without affecting the users of the method.

The Beauty of Encapsulation

Now, in my opinion, to understand encapsulation, one must first understand abstraction.

Think, for example, in the level of abstraction in the concept of a car. A car is complex in its internal implementation. They have several subsystems, like a transmission system, a brake system, a fuel system, etc.

However, we have simplified its abstraction, and we interact with all cars in the world through the public interface of their abstraction. We know that all cars have a steering wheel through which we control direction, they have a pedal that when you press it you accelerate the car and control speed, and another one that when you press it you make it stop, and you have a gear stick that let you control if you go forward or backward. These features constitute the public interface of the car abstraction. In the morning you can drive a sedan and then get out of it and drive an SUV in the afternoon as if it was the same thing.

However, few of us know the details of how all these features are implemented under the hood. Think of the time when cars did not have a hydraulics directional system. One day, the car manufactures invented it, and they decide it to put it in cars from there on. Still, this did not change the way in which users were interacting with them. At most, users experienced an improvement in the use of the directional system. A change like this was possible because the internal implementation of a car is encapsulated. Changes can be safely done without affecting its public interface.

Now, think that car manufacturers decided to put the fuel cap below the car, and not in one of its sides. You go and buy one of these new cars, and when you run out of gas you go to the gas station, and you do not find the fuel cap. Suddenly you realize it's below the car, but you cannot reach it with the gas pump hose. Now, we have broken the public interface contract, and therefore, the entire world breaks, it falls apart because things are not working the way it was expected. A change like this would cost millions. We would need to change all gas pumps in the world. When we break encapsulation we have to pay a price.

So, as you can see, the goal of encapsulation is to minimize interdependence and facilitate change. You maximize encapsulation by minimizing the exposure of implementation details. The state of a class should only be accessed through its public interface.

I really recommend you to read a paper by Alan Snyder called Encapsulation and Inheritance in Object-Oriented Programming Languages. This link points to the original paper on ACM, but I am pretty sure you will be able to find a PDF copy through Google.

Edwin Dalorzo
  • 76,803
  • 25
  • 144
  • 205
  • 8
    Great Response . especially when u summed up your comments in these 3 lines "So, as you can see, the goal of encapsulation is to minimize interdependence and facilitate change. You maximize encapsulation by minimizing the exposure of implementation details. The state of a class should only be accessed through its public interface." .. Nice Job! – Just_another_developer Aug 28 '12 at 06:01
  • Nicely explained. But, I didn't understand one thing where you said: `"The beauty of encapsulation is the power of changing things without affecting its users."` Now, taking the context of `java`, what is `"users"` here ? Does it mean `end users` of the java application ? Does it mean that `part of java code or module` which is going to use the public interfaces? Does it mean the `java programmers` who are going to refer or call those public interfaces? – oblivion Feb 04 '17 at 16:27
  • 1
    @oblivion It means the users of your API, the persons who would actually use it to solve a problem. – Edwin Dalorzo Feb 04 '17 at 16:29
  • So, basically `encapsulation` is not actually `hiding` the implementation. It is more about `separating the implementation and users` by keeping public interfaces between them. This is done to address future changes in `implementation` and `easier code maintenance`. Am I understanding this correctly ? – oblivion Feb 04 '17 at 16:37
  • @oblivion Well, the public interface of an object is typically a smaller subset of all the functionality the implementation actually has, so the public interface is always a smaller view of what the object exposes publicly. I daresay then, the rest is hidden from the API users simply because those details should be irrelevant for them, e.g. I just want that when I turn the wheel of the car left it goes left, implement it however you want. Your insights are correct, the intention is to make implementation easier use and the code maintainable and malleable but without breaking the clients. – Edwin Dalorzo Feb 04 '17 at 17:05
  • @oblivion It is important to understand that when I say "public interface" I am not talking of Java interfaces. I am talking of interfaces in a broader object-orientation concept, the actual concept that gave origin to the idea of Java interfaces when the language was defined. Public interface means the functionality or behavior an object is supposed to expose to others. In Java you can define those interfaces and public methods in a class. This is what an object exposes to its API users and therefore its public interface. – Edwin Dalorzo Feb 04 '17 at 17:10
  • @oblivion If an object is used in an inheritance chain, it also has a protected interface, which is the functionality that it makes available to child classes. Typically a parent class share more with its subclasses than what it shares with its public users, which gives origin to this another layer of encapsulation that it is also important to handle correctly to avoid excessive coupling. – Edwin Dalorzo Feb 04 '17 at 17:12
  • 2
    @oblivion You may also like to read [Abstraction, Encapsulation, and Information Hiding](http://www.tonymarston.co.uk/php-mysql/abstraction.txt) – Edwin Dalorzo Feb 04 '17 at 17:14
  • Thanks for the article link. That really gave me the idea about the precise differences between the 3 concepts`(abstraction, hiding and encapsulation)` at a higher level. – oblivion Feb 04 '17 at 17:48
  • Could you elaborate on the private instance variable `javafx.scene.Camera` inside `javafx.scene.Scene` class? An extra layer of abstraction/encapsulation is added by putting the actual instance variabe content inside a `javafx.beans.property.ObjectProperty`. The way it is made make a Setter/Getter method look like barbarism. Is there other reasons aside of being able to add listeners of doing it that, in what situation would it be benifical to use that instead of the "simple" Setter/Getter approach? – Lealo Oct 04 '17 at 23:51
  • 1
    @Lealo, it would be very hard to just comment on that. My suggestion is that you open a question about it and make a reference to this post, that way you could get an extensive answer. – Edwin Dalorzo Oct 05 '17 at 00:09
16

The way I understand your question is, although we declare variables as private, as those variables can be accessed using getters and setters, they are not private. Therefore, what is the meaning of doing that?

Well, when using getters and setters, you can restrict access to the private variables.

I.e.,

private int x;

public int getInt(String password){
 if(password.equals("RealPassword")){
   return x;
  }
}

And the same for the setters.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mithilatw
  • 908
  • 1
  • 10
  • 29
  • 1
    yes, it helped, it's a good example ...but normally we are not passing values to getters instead we are getting values returned.. Doesn't it breaks the conventions? or doesn't it falsify the encapsulation properties? – Just_another_developer Aug 15 '12 at 09:31
  • 3
    (There is no / I haven't heard of) such convention to not to pass parameter values to getters! (They are parameter values rather than explicit values) And in terms of setters, you can pass multiple parameters to the method. – mithilatw Aug 15 '12 at 09:36
  • There are also a encapsulation way of using `ObjectProperty` that I have seen in the *javafx.scene.Scene* class among other places (look at the private instance variable `camera` in `Scene` class). I do not exactly grasp the benefit of it or how it is used but I can certainly scent there is some benefit of doing this. – Lealo Oct 04 '17 at 23:44
  • I don't think this is a good example. getters and setters should get and set, nothing else. And your example won't compile - what happens if it's not the real password? Do you return 0, or -1? How does the caller know that the real value hasn't been returned? – pecks Oct 06 '17 at 13:59
13

The data is safe, because you can do additional logic in your getter / setter, and it's not possible to change the values of your variable. Imagine your code did not work with a null variable, so in your setter you can check against null values and assign a default value which is != null. So your code is still working, regardless of whether someone tries to set your variable to null.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
markus
  • 602
  • 4
  • 13
5

My question is if we can access the variables (data) though via getters and setters, how come data is hidden or safe?

You can encapsulate the logic under getters/setters. For example,

public void setAge(int age) {
    if (age < 0) {
        this.age = 0;
    }
    else {
        this.age = age;
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jmj
  • 237,923
  • 42
  • 401
  • 438
  • Is this the only explanation? – Just_another_developer Aug 15 '12 at 09:20
  • Although I get the point in the example, the truth is that in a case like this I'd rather throw a IllegalArgumentException instead of silently set the age to 0. Any attempt to set age to a negative value would be, evidently, an error and should be made evident as soon as possible with an exception. Don't you agree? – Edwin Dalorzo Sep 29 '12 at 15:55
  • 1
    This is just an illustration how we encapsulate the stuff, it depends on application business logic whether to raise exception or ignore the passed value and set with the default value – jmj Sep 29 '12 at 15:56
4

Continuing Jigar's answer: There are a couple of things that come under encapsulation.

  1. Contract Management: If you make it public, you are literally making anyone to change it to whatever they want. You can't protect it by adding a constraint. Your setter can make sure data gets modified in an appropriate way.

  2. Mutability: You do not always have to have a setter. If there is a property that you wanted to keep immutable for the life span of the object. You just make it private and have no setter for it. It will probably be set via constructor. Then your getter will just return the attribute (if it's immutable) or a copy of the attribute (if attribute is mutable).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Nishant
  • 54,584
  • 13
  • 112
  • 127
3

In general, encapsulation of fields by getters and setters leaves more flexibility for changes.

If fields are accessed directly you are stuck with "stupid fields". Fields can only be written and read. Nothing else can be done while accessing a field.

When using methods you can do whatever you want while setting / reading the value. As markus and Jigar mentioned, validation is possible. In addition, you could decide some day that the value is derived from another value or some actions must be executed if the value changes.

how come data is hidden or safe

Data is neither hidden nor safe by using getters and setters. It just gives you the possibility to make it safe. What is hidden is the implementation and not the data.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Markus Kreusch
  • 2,071
  • 3
  • 19
  • 33
2

Data validation is the main answer to your question regarding how encapsulation provides safety if there are accessors and/or mutators in play. Others have mentioned this using examples of having a fail-safe to set a default value in the mutator. You replied that you prefer throwing exceptions instead, which is great, but identifying that you have bad data when you go to use it does not change the fact that you have bad data. Would it therefore not be best to catch the exception before data is modified, i.e., do it in the mutator? This way the actual data is never modified unless the mutator has verified it as being valid, thus the original data is preserved in the event of bad data.

I'm still just a student myself, but I had the same exact though as you when I first encountered encapsulation, so I spent some time figuring it out.

Grim0013
  • 86
  • 6
1

I like the explanation when taking into consideration threads. If you made your fields public, how is your instance going to know when a certain thread changed one of its fields?

The only way to do it would be with encapsulation, or simpler put give getters and setters to that field, thus you always know and can check/react to fields updates, for example.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Eugene
  • 117,005
  • 15
  • 201
  • 306
0

Encapsulation makes code more easy to reuse by other people. Another key reason to use encapsulation is that interfaces can not declare fields, but they can declare methods, which can refer to a field!

Methods are properly named with a verb at the beginning. Such as: getName(), setName(),isDying(). Which can help read code!

blockay
  • 17
  • 8