4

In encapsulation the idea is that you hide what your class is doing with its variables by declaring them private, which achieves the OCP. But then why would you then add getters and setters, which then opens up your variables for modification?

Why go through the whole trouble of setting your variables as private, to then add a public setter on them? That doesn't seem very restrictive, which is one of the ideas of encapsulation.

liloka
  • 1,016
  • 4
  • 14
  • 29

7 Answers7

7

opens up your variables for modification

In Open-Closed Principle, the word "open" means something entirely different.

It means that the source code of the class is closed for modification, but the resulting class artifact is open for further modification by extension. Neither "open" nor "closed" refers to any aspect of the instances of the class.

On the other hand, I am with you on the critique of getters/setters from a slightly different angle: they add a huge amount of boilerplate just to revert your overall design to something almost identical to a class with public fields.

In some cases, which are less commonplace, it still pays to gave getters/setters. This is true for classes which belong to a public API of a library, and generally to any class which has some non-trivial behavior, configured through the setters.

For pure data classes, getters/setters are mainly forced into them by the requirements of outdated frameworks which refuse to work with public fields. Spring, Hibernate, and Jackson are examples of state-of-the-art frameworks which do not force this.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • Ah, now I get the difference with the Open-Closed principle. But here it does say: Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification, which I would take as instance variables as well so it just felt redundant. – liloka Dec 17 '13 at 12:15
  • 3
    Exactly, you just need to read carefully: it is the **class** which is closed for modification, not its **instances**. – Marko Topolnik Dec 17 '13 at 12:16
4

Setting a variable directly gives control to outside code like

class A {
    public String a;
}
A a = new A();
a.a = "bad value which will cause code fail"

But in case of getters and setters,

class A {
    private String a;

    public void setA(String a) {
       if(! "some bad value".equals(a) ) {
           this.a = a;
       }

    }
}

So, using getters and setters will give the control with our class instance and not other possible bad class.

Costi Ciudatu
  • 37,042
  • 7
  • 56
  • 92
Yogesh Patil
  • 908
  • 4
  • 14
4

Here you are.
Assuming this is my instance variable

private double x;

By using Setters, you can make your own validation on the value will be set to the instance variable.

public void setX(double x)
{
    if (x <= 0)
        System.out.println("Wrong value, value should be greater than 0");
    else
        this.x = x;
}

By using Getters, you will be able to return the data in the format you want the user to see.

public double getX()
{
    return Double.valueOf(String.format("%.3f", this.x));
}
Ahmed Hamdy
  • 2,547
  • 1
  • 17
  • 23
  • 1
    Why is it you never see validation in a setter? – liloka Dec 17 '13 at 12:13
  • +1 Exactly my point... putting validation into a setter breaks the *separation of concerns* principle and makes your class *less useful* because it won't work in the setting where the validation is inappropriate. There are complete *bean validation* frameworks which systematically deal with this concern, and that is the way to go. – Marko Topolnik Dec 17 '13 at 12:14
  • Depends on the validation. If it's business rules, it should be separated (an be configurable). If it's technical validation such as checking for null-values or positive values or something state-driven (SWT classes which check if the widget is disposed when setting values), it might be appropriate. – Peter Walser Dec 17 '13 at 12:19
  • So far this is just the biggest trade-off in computing, because you're choosing between 3 principles, if not more here. Why would it break the SoC principle since it should be concerned if the variable is being correctly set? – liloka Dec 17 '13 at 12:20
  • @liloka In that case, you can use them as public. We still use the setter even without validation because we are always use information hiding concepts, besides may be you will need to add some validation later, so I will not change the calling technique. Another good example is that of I changed the data type of this instance variable and I didn't want to change the user calling, I just will delegate that in the setter, so the caller will never feel the deference, and in the next program update I can make the changes – Ahmed Hamdy Dec 17 '13 at 12:23
  • @iloka Many kinds of validation in business objects depend on the context. Another concern is validation which involves more than the property being set; then your validation code may introduce constraints on the order of setting individual properties. The point is not that setter validation is *never* appropriate; the point is that *many times* it isn't so this can't support a blanket statement that setters are always, without exception, the better road to take than public fields. – Marko Topolnik Dec 17 '13 at 12:36
  • If you have to worry about separation of concerns among different methods in a class your class carries way too many responsibilities. A much better way to separate concerns is to have each class do one thing only. – Nicola Musatti Dec 17 '13 at 12:41
  • @NicolaMusatti Validation is a separate concern. It has nothing at all to do with the separation of concerns among different methods in a class. – Marko Topolnik Dec 17 '13 at 12:44
  • Validation may be a good reason to have a setter, but you should wonder whether your attributes are really so loosely coupled that it makes sense to change one independently of the others. If it does, do they really belong together or is your class catering for what should really be independent concerns. – Nicola Musatti Dec 17 '13 at 12:45
  • We are using the term "validation" to mean different things: I'm thinking about ensuring that a class's state is consistent with the class's purpose. By the way, State consistency is the key argument against setters. – Nicola Musatti Dec 17 '13 at 12:47
  • @NicolaMusatti Have you ever worked on an actual business application project, involving actual business objects? They are just hierachically organized tuples of atomic data bits. Most of them are completely independent, which doesn't begin to entail that each of them should be in a class of its own. – Marko Topolnik Dec 17 '13 at 12:50
  • We seem to be using very different design approaches. – Nicola Musatti Dec 17 '13 at 12:56
  • 1
    You are being offensive without reason. You don't know anything about me or my work. – Nicola Musatti Dec 17 '13 at 13:05
  • @NicolaMusatti Exactly, I don't know anything---that is why I have specified my premises in detail. *If* they are true, *then* I stand by my conclusion. You should also notice that the premises are of a *strawman hypothesis* variety, used as a device to drive my point through exaggeration. I also notice you have resorted to the tactics of evasion and changing the subject instead of meeting my arguments. – Marko Topolnik Dec 17 '13 at 13:29
  • Can anyone tell me why my answer being removed as the correct answer :/ ? @liloka – Ahmed Hamdy Dec 18 '13 at 09:22
  • I just changed it to the one with the most upvotes, as it seemed the most voted as the right answer, for future references. – liloka Dec 18 '13 at 10:36
  • 1
    @liloka Okay, it is just not working like this :D But anyways I was just clarifying, it is okay. – Ahmed Hamdy Dec 18 '13 at 10:58
2

Encapsulation is about hiding implementation details.

Your getter and setter methods are about part of the published API for your class and provide a well defined way to see what is happening.

Internally you could rip out all the implementation and do something completely different, but by maintaining the same set and get methods this change is invisible to every other class.

An API should be about the things that the person using it wants to do, not the internal details of how you do it.

For example if you have a class to connect to a server and have a string containing the name and port and expose that string now you are tied to that.

If in the future you want to split it and store name and port separately you cannot do so because people might be reading or setting that string directly - and you will break the code for everyone who does so.

Or even worse suppose you keep it stored the same - but you need to know when it changes. It's impossible to do that (well actually there are a number of hacky ways like storing what the string held last time you looked and checking for changes, or having a thread running to look for changes etc, all these methods are hacky and inefficient though)

Tim B
  • 40,716
  • 16
  • 83
  • 128
1

By having setters and getters, you can

  • Hide the actual implementation (not every property has to be backed up by a variable, could as well be a caculated property, or a converted property, or the value is read/written from elsewhere)
  • Restrict access, by only providing getters for those properties you want to expose, and only providing setters for properties you want to allow to be modified
  • Control access, for example rejecting values when they are not correct, or when accessing with insufficient privileges
  • Add observer support, by guarding state changes and firing change events when something changes
  • Trigger logic when values are read/) written
  • and much more.
Peter Walser
  • 15,208
  • 4
  • 51
  • 78
1

In general you should design separately the interface to a class, i.e. how you expect your class to be used, from its implementation, i.e. how it works. By doing so it may happen that some of your methods end up doing little more than setting or getting an attribute's value.

However you should do it only when it makes sense rather than as a general approach.

What really doesn't make any sense are classes with only private attributes, a setter/getter public method for each attribute and no other method. There are situations were you do need to move a few values together without any specific logic that binds them; in that case you should define a class with only public attributes and no methods, except possibly a constructor.

Nicola Musatti
  • 17,834
  • 2
  • 46
  • 55
1

You're absolutely right about blatantly adding setters/getters to every private member being a violation of encapsulation and OCP.

To explain the paradox, OCP requires some context (i.e., closed relative to what?). At a class-design level, OCP means clients of the (public part of the) class won't have to change if you change the (private) implementation details. The private parts of a class are open to change, relative to the clients using the closed (public) interface.

Adding a getter/setter for every private variable will violate OCP. It's the same as making every private attribute a public one (except for the validation aspects some other answers have mentioned, but those are not big points in my opinion). For more explanation about why this is bad, see Why getter and setter methods are evil.

Rather than design methods based on implementation details (getters and setters), try to consider the public interface of a class as a set of "services" or "responsibilities" that class offers to the system. Those services should hide the implementation details if possible. Think of how clients of the class are going to use it. See more in Responsibility-driven design.

As for getters and setters, they aren't always bad. Just think twice before adding them. Public methods are a kind of promise to clients of the class that you're supporting a service (clients who use that class will break if you change the public interface). You might make it harder for yourself to change the details of the class if you're revealing them in the public interface.

There's another angle to consider when you return (via get) a reference to an object that is part of an implementation detail. The client who gets that reference can then possibly manipulate the object (get reveals implementation details). For example, Student.admissionDate:Date has a getter that returns a reference to the Date. A client of the Student class could get the date, and change it. To avoid this, the getter should return a clone of the object. In Java it would be return (Date)admissionDate.clone()

Fuhrmanator
  • 11,459
  • 6
  • 62
  • 111