tags:

views:

340

answers:

9

I recently read that getters/setters are evil and I have to say it makes sense, yet when I started learning OOP one of the first things I learned was "Encapsulate your fields" so I learned to create class give it some fields, create getters, setters for them and create constructor where I initialize these fields. And every time some other class needs to manipulate this object (or for instance display it) I pass it the object and it manipulate it using getters/setters. I can see problems with this approach.

But how to do it right? For instance displaying/rendering object that is "data" class - let's say Person, that has name and date of birth. Should the class have method for displaying the object where some Renderer would be passed as an argument? Wouldn't that violate principle that class should have only one purpose (in this case store state) so it should not care about presentation of this object.

Can you suggest some good resources where best practices in OOP design are presented? I'm planning to start a project in my spare time and I want it to be my learning project in correct OOP design..

+1  A: 

Why do you think getters are evil? See a post with answers proving the opposite:

Purpose of private members in a class

IMHO it contains a lot of what can rightfully be called "OOP best practices".

Update: OK, reading the article you are referring to, I understand more clearly what the issue is. And it's a whole different story from what the provocative title of the article suggests. I haven't yet read the full article, but AFAIU the basic point is that one should not unnecessarily publish class fields via mindlessly added (or generated) getters and setters. And with this point I fully agree.

By designing carefully and focusing on what you must do rather than how you'll do it, you eliminate the vast majority of getter/setter methods in your program. Don't ask for the information you need to do the work; ask the object that has the information to do the work for you.

So far so good. However, I don't agree that providing a getter like this

int getSomeField();

inherently compromises your class design. Well it does, if you haven't designed your class interface well. Then, of course, it might happen that you realize too late that the field should be a long rather than an int, and changing it would break 1000 places in client code. IMHO in such case the designer is to blame, not the poor getter.

Péter Török
He didnt say he thinks they're evil, but that he read that they are.
lugte098
I don't mean you should be using public fields of course, what I meand that you shouldn't be exposing any details about class implementation in this case what fields it has unless absolutely necessary. The article is here http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html
kane77
@lugte098 "I recently read that getters/setters are evil and I have to say it makes sense"
Péter Török
@kane77 see my update.
Péter Török
@Peter, sorry to come off as provocative, I was just curious to know how far or how seriously this should be taken.And I agree, the example is not that good and if the design is bad it can happen even for non getter methods
kane77
@kane77 "provocative" referred to the article you cited, not your post - excuse me if this was not clear. I don't have any problem with your post (except that you should have included a link to that article first thing :-) It is in fact really good that you are reading, trying out things, educating yourself - keep up with it, and keep asking questions at SO as well - this discussion was educating for me also.
Péter Török
+5  A: 

Allen Holub made a big splash with "Why getter and setter methods are evil" back in 2003.

It's great that you've found and read the article. I admire anybody who's learning and thinking critically about what they're doing.

But take Mr. Holub with a grain of salt.

This is one view that got a lot of attention for its extreme position and the use of the word "evil", but it hasn't set the world on fire or been generally accepted as dogma.

Look at C#: they actually added syntactic sugar to the language to make get/set operations easier to write. Either this confirms someone's view of Microsoft as an evil empire or contradicts Mr. Holub's statement.

The fact is that people write objects so that clients can manipulate state. It doesn't mean that every object written that way is wrong, evil, or unworkable.

The extreme view is not practical.

duffymo
Actually - Mr Holub article is quite right. Just title sounds extreme. It's sad, that people stop reading after it :/
MaR
@MaR Totally agree, it needlessly antagonizes a lot of people who otherwise would be open to hear what you have to say.
Andreas Brinck
I read the article. Allen Holub is a very smart guy, but the fact is that nobody is following his advice. Objects are still being written, code is running, and any problems that might arise cannot be placed at the feet of writing getters and setters. It's an academic argument at this point.
duffymo
Thanks for your oppinion. Yes, I like to think critically and challenge all my beliefs,and I try to consider things before rejecting them. This is one of them, when I wrote that I think it makes sense I don't mean that I 100% agree with Mr. Holub, it certainly makes sense to keep getters and setters to minimum, but I don't think it's possible to replace 99% of (g/s)etters as he claims..
kane77
+2  A: 

"Encapsulate your fields" so I learned to create class give it some fields, create getters, setters

Python folks do not do this. Yet, they are still doing OO programming. Clearly, fussy getters and setters aren't essential.

They're common, because of limitations in C++ and Java. But they don't seem to be essential.

Python folks use properties sometimes to create a getter and setter functions that look like a simple attribute.

The point is that "Encapsulation" is a Design strategy. It has little or nothing to do with the implementation. You can have all public attributes, and still a nicely encapsulated design.

Also note that many people worry about "someone else" who "violates" the design by directly accessing attributes. I suppose this could happen, but then the class would stop working correctly.

In C++ (and Java) where you cannot see the source, it can be hard to understand the interface, so you need lots of hints. private methods, explicit getters and setters, etc.

In Python, where you can see all the source, it's trivial to understand the interface. We don't need to provide so many hints. As we say "Use the source, Luke" and "We're all adults here." We're all able to see the source, we don't need to be fussy about piling on getters and setters to provide yet more hints as to how the API works.

For instance displaying/rendering object that is "data" class - let's say Person, that has name and date of birth. Should the class have method for displaying the object where some Renderer would be passed as an argument?

Good idea.

Wouldn't that violate principle that class should have only one purpose (in this case store state) so it should not care about presentation of this object.

That's why the Render object is separate. Your design is quite nice.

No reason why a Person object can't call a general-purpose renderer and still have a narrow set of responsibilities. After all the Person object is responsible for the attributes, and passing those attributes to a Renderer is well within it's responsibilities.

If it's truly a problem (and it can be in some applications), you can introduce Helper classes. So the PersonRenderer class does Rendering of Person data. That way a change to Person also requires changes to PersonRenderer -- and nothing else. This is the Data Access Object design pattern.

Some folks will make the Render an internal class, contained within Person, so it's Person.PersonRenderer to enforce some more serious containment.

S.Lott
With Python vs Java, it is also a syntax issue - with Python, the syntax to access a field is the same as the syntax to read from a getter. This means you can change the implementation without affecting all the code which uses the class. With Java, the implementation difference is exposed to consumers of the class, they either do instance.foo or instance.getFoo(), so a change to the implementation ripple through the dependencies. With Python (and Ruby and C#) it is always instance.foo, so no dogmatic "always encapsulate your fields" rule is required.
Douglas
A: 

Anything that is public is part of the API of the class. Changing these parts may break other stuff, relying on that. A public field, that is not only connected with an API, but with internal representation, can be risky. Example: You save data in a field as an array. This array is public, so the data can be changed from other classes. Later you decide to switch to a generic List. Code that use this field as an array is broken.

Mnementh
i think that's what the discussion is trying to get at. do you leave it public and open it up to such abuse, or mindlessly create getters and setters and then open it up to such abuse.
Anurag
+4  A: 

If you have getters and setters, you don't have encapsulation. And they are not necessary. Consider the std::string class. This has quite a complicated internal representation, yet has no getters or setters, and only one element of the representation is (probably) exposed simply by returning its value (i.e. size()). That's the kind of thing you should be aiming for.

anon
I agree with you even though I don't think `std::string` is the best example. The two `operator []` in the string actually is a form of get/set functions.
Andreas Brinck
+1  A: 

Assume you have many entity classes in your designs, and suppose they have a base class like Data. Adding different getter and setter methods for concrete implementations will pollute the client code that uses these entities like lots of dynamic_casts, to call required getter and setter methods.

Therefore, getter and setter methods may remain where they are, but you should protected client code. My recommendation would be to apply Visitor pattern or data collector for these cases.

In other words, ask yourself why do I need these accessor methods, how do I manipulate these entities? And then apply these manipulations in Visitor classes to keep client code clean, also extend the functionality of entity classes without polluting their code.

baris_a
+1  A: 

In some languages, like C++, there's the concept of friend. Using this concept you can make implementation details of a class visible to only a subset of other classes (or even functions). When you use Get/Set indiscriminately you give everyone access to everything.

When used sparingly friend is an excellent way of increasing encapsulation.

Andreas Brinck
+1  A: 

The basic concept of why they are considered to be evil is, that a class/object should export function and not state. The state of an object is made of its members. Getters and Setters let external users read/modify the state of an object without using any function.

Hence the idea, that except for DataTransferObjects for which you might have Getters and a constructor for setting the state, the members of an objects should only be modified by calling a functionality of an object.

ogni42
+1  A: 

In the following paper concerning endotesting you'll find a pattern to avoid getters (in some circumstances) using what the author calls 'smart handlers'. It has a lot in common with how Holub approaches avoiding some getters.

http://www.mockobjects.com/files/endotesting.pdf

koen