Senior Java developer, one of the top stackoverflow users, fluent with Java and Java technology stacks - Spring, JPA, JavaEE. Founder and creator of http://computoser.com and http://welshare.com . Worked on Ericsson projects, Bulgarian e-government projects and large scale recruitment platforms. Member of the jury of the International Olympiad in Linguistics and the Program committee of the North American Computational Linguistics Olympiad. Bozhidar is a DZone MVB and is not an employee of DZone and has posted 81 posts at DZone. You can read more from them at their website. View Full User Profile

Getters and Setters Are Not Evil

10.14.2011
| 9146 views |
  • submit to reddit

Every now and then some OOP purist comes and tells us that getters and setters are evil, because they break encapsulation. And you should never, ever use getters and setters because this is a sign of a bad design and leads to maintainability nightmares.

Well, don’t worry, because those people are wrong. Not completely wrong of course, because getters and setters can break encapsulation, but in the usual scenario for regular business projects they don’t. What is the purpose of encapsulation? First, to hide how exactly an object performs its job. And to protect the internal data of an object, so that no external object can violate its state space. In other words, only the object knows which combination of field values is valid and which isn’t. Exposing fields to the outside world can leave the object in inconsistent state. For example what if you could change the backing array in an ArrayList, without setting the size field? The ArrayList instance will be inconsistent and will be violating its contract. So no getter and setter for the array list internal array.

But the majority of objects for which people generate getters and setters are simple data holders. They don’t have any rules to enforce on their state, the state space consists of all possible combinations of values, and furthermore – there is nothing they can do with that data. And before you call me “anemic”, it doesn’t matter if you are doing “real OOP” with domain-driven design, where you have business logic & state in the same object, or you are doing fat service layer + anemic objects. Why it doesn’t matter? Because even in domain-driven projects you have DTOs. And DTOs are simply data holders, which need getters and setters.

Another thing is that in many cases your object state is public anyway. Tools use reflection to make use of objects – view technologies use EL to access objects, ORMs use reflection to persist your entities, jackson uses reflection to serialize your objects to JSON, jasper reports uses reflection to get details from its model, etc. Virtually anything you do in the regular project out there requires data being passed outside of the application: to the user, to the database, to the printer, as a result of an API call. And you have to know what that data is. In EL you have ${foo.bar} – with, or without a getter, you consume that field. In an ORM you need to know what database types to use. In the documentation of your JSON API you should specify the structure (another topic here is whether rest-like services need documentation). The overall point here is that you win nothing by not having getters and setters on your data holder objects. Their internal state is public anyway, and it has to be. And any change in those fields means a change has to be made in other places. Change is something people fear – “you will have to change it everywhere in your project” .. well, yeah, you have, because it has changed. If you change the structure of an address from String to an Address class, it’s likely that you should revisit all places it is used and split it there as well. If you change a double to BigDecimal you’d better go and fix all your calculations.

Another point – the above examples emphasized on reading the data. However, you must set that data somehow. You have roughly 3 options – constructor, builder, setters. A constructor with 15 arguments is obviously not an option. A builder for every object is just too verbose. So we use setters, because it is more practical and more readable.

And that’s the main point here – setters and getters are practical when used on data holder objects. I have supported quite big projects that had a lot of setters and getters, and I had absolutely no problem with that. In fact, tracing “who sets that data” is the same as “where did this object (that encapsulates its data) came from”. And yes, in an ideal OO world you wouldn’t need data holders / DTOs, and there will be no flow of data in the system. But in the real world there is.

To conclude – be careful with setters and getters on non-data-only objects. Encapsulation is a real thing. When designing a library, a component or some base frameworks in your project – don’t simply generate getters and setters. But for the regular data object – don’t worry, there’s no evil in that.

 

From http://techblog.bozho.net/?p=621

Published at DZone with permission of Bozhidar Bozhanov, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Fabrizio Giudici replied on Fri, 2011/10/14 - 2:33am

 

Before saying that I mostly disagree, I think it's necessary to make a preamble. "Evil" and "good" are often misused in our world. I think they are good for a brief title or for telling things with some humour, but "appropriate" and "unappropriate" are better terms. In other words, there's no black and white, but a scale of greys. There's no "true OOP" in practice, you can do things in many ways, paying some costs and getting benefits. The important thing is that you are aware of your choice, I mean, you are aware of what you are going to pay and what are you going to get, and you are consistent.

The basic point is not related to the danger of exposing the internal state. It's to depend on a public thing. For instance, if I have a Person with firstName, lastName and age properties, and I use them by means of getters, my whole application potentially depends on these three properties. If any of these properties change (let me say it disappears), you have broken code potentially everywhere. Of course, it's unlikely that a firstName, lastName disappears from a Person. So in this very example, one might assume that the risks of going with getter / setters are low. Let's just think of a more complex domain where properties are more likely to change.

In this case, the risks might be higher. What I'd do is not to expose those properties as public, but as package friends. If I have to render Person e.g. on a web page, I'd write a PersonRenderer which has a method render(Person, WebPage) [with WebPage I mean any infrastructure related to a give web technology to render something] which does the job. Should I send an email to that person, I'd use a similar friend class PersonEmailer, etc. With this approach, I know that the dependencies on the structure of Person are well known in advance and I can predict what impact will have any change in the structure of Person (of course, I can say the impact is very small).

Is it better or not? Sure, it's more complex, because I have more classes (even though they are very small and simple). I've written and Android application using this approach and, once you've understood it, it's not that difficult. But I agree, it's not necessarily always the best solution. See my preamble. 

For what concerns DTO in DDD, there's a way to fix the anemic object thing which make it also possible to work without getter/setters: DCI. Google for DCI and read the Artima's article for quickly learning on it. In short, your entities get decomposed in an anemic object (what would be he DTO, called Datum) and a number of active classes (Roles) doing operations on it. Roles are not services, since there's an instance of Role per each Datum. Without getter/setters the Datum basically has no methods. I'd have person.getRenderer().renderTo(renderable) for rendering it, or person.getEmailer().sendEmailTo(recipient) in a simple fashion. If I am concerned about decoupling dependencies, I can have a dynamic approach as person.getRole(Renderer).renderTo(renderable) [or a better syntax that I prefer, person.as(Renderer).renderTo(renderable)], and roles can be dynamically injected in a number of ways.To deal with frameworks that absolutely want getters/setters as JPA, I can have person.as(Persistable).persist(), where the specific implementation of Persistable would copy the internal state of Person into a JPAPersonBean and do the job trasparently.  You get that I have another advantage here, that I can replace the persistence mechanism as I want.
 
This is very powerful, very extensible, very robust. It costs a bit more than a plain design with getters/setters. In a way, I think it's a very appropriate way to use OOP, since the Single Responsibility Principle is respected to a very fine grain. In some cases, though, it can cost too much for the purpose. 

Alexandru Repede replied on Fri, 2011/10/14 - 3:54am

actually, getters are evil (because they expose internal state). setters pretty much serve very well the purpose of initializing a big object, as an alternative to constructors.

getters, indeed, are not entirelly evil, in the context of ORM (this seems the only area that actually makes reasonable use of getters)

the alternative to getters, in the context of getting that data and processing on it, would be the principle "tell, don't ask". the basic idea is to tell the object that has the data to do the desired processing on that data (instead of getting the data and processing it in another class). sure, delegation is an option inside an object that stores lots of data or might have lots of functionalities around that data

this is where the idea that the object programming model mimics reality really breaks, because you don't tell things to go this and that, but something/somebody else does the action on a thing. for example, turn lights on, while in OOP you say Lights.on(), as in, turn yourself on.

another issue to discuss would be alternatives to setters. you mentioned builders, but there are also inner classes. in the idea of immutability, and aiming to internal DSLs, you can do something like this: DSL example as a GitHub Gist

it looks a bit complicated (as mentioned by Fabrizio Giudici, things will get complicated); but, it's work in progress for me, as i'm exploring the idea, i'm hoping to improve; well, it's not perfect yet. anyway, it will be bit more complex, but it's supposed to save your arse later

Caspar MacRae replied on Sun, 2011/10/16 - 4:09pm

Can we please remove the words "not" and "setter" from the title and replace the article body with the content of @Alexandru's reply.

Beans are the product of  Sun's one-size fits all JEE pap and result in huge, procedural, ugly and anemic apps.  We have lots of clever ways for frameworks to lazy-load etc without forcing us to bugger encapsulation and violate the Law of Demeter.

@Bozhidar needs to be more clear, there's nothing wrong with exposing fields if the object is just a data structure (a record or struct in non Java languages), but in that case there's nothing wrong with having public fields (cue gasps all round) even better if they're immutable

 

 


 


Lund Wolfe replied on Sat, 2011/10/15 - 3:56am

If you're stuck in a bean type situation, you may have to provide a pure bean type data class complete with getters and setters on each data member. It's ugly but required. Sometimes, you just have a data holder used by one or two trusted classes that need and use it, so you can just let those classes directly access the data. If the data types/structure changes those classes will have to change anyway.

Don't clutter the data class with getters/setters. Getters/setters are just plain ugly. I would start out with hidden/private access of data and only add getters/setters as needed for external access. If usage is expected to expand or be public, then wrap the internal private implementation data in methods like getters/setters to make it obvious and maintainable and deep copy non primitive data in and out rather than totally exposing the internal data. I think getters/setters are ugly, but general direct data access or mixed data and method access to data is that much uglier.

Put the data in a business object that provides some kind of business API rather than data access and let the user set it through a constructor only (pass in a throwaway data holder if there are too many arguments) if possible.

Fuqiang Zhao replied on Sat, 2011/10/15 - 4:55am

They are not evil, c# attribute is better than this way!

Balázs Bessenyei replied on Sun, 2011/10/16 - 3:18am in response to: Fuqiang Zhao

Nope, they are the same. C# uses syntactic sugar to generate getters and setters for class attributes, transparent to the developer.

Hontvári József... replied on Sun, 2011/10/16 - 8:06pm in response to: Fabrizio Giudici

Of course, it's unlikely that a firstName, lastName disappears from a Person.

Ironically, no. After the internationalization of the application is started, it will become obvious that using the firstName, lastName fields was not that great idea after all. See Falsehoods Programmers Believe About Names. My favorite from the list of false assumptions: People have names.

Fuqiang Zhao replied on Mon, 2011/10/17 - 8:16pm in response to: Balázs Bessenyei

I like the new Java property proposal by Rémi Forax, the get and set methods could be removed for most Domain Objects.

Balázs Bessenyei replied on Sat, 2011/10/22 - 4:12pm in response to: Fuqiang Zhao

Basically this will be the same as Project Lombok (new keyword instead of annotation). It will not change the fact that the getters and setters are still there, just not directly written out. 

The article and most of the commenters have no problem with getters and setters in general. They have a problem with what they allow you to do. Namely access and mutate the "internal state" of an object. "Hiding" the getters and setters with syntactical sugar will not solve this.

The proposal is interesting however there is a big question. How they are planing to solve the getter/setter generation. If they do it in way that can changes the line number information between the source and the compiled class. Then this feature will be banned in any sane environments.
Also this solution can obscure even more the NPE when Autoboxing is used. 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.