views:

4737

answers:

16

I'm currently working on a simple game in Java with several different modes. I've extended a main Game class to put the main logic within the other classes. Despite this, the main game class is still pretty hefty.

After taking a quick look at my code the majority of it was Getters and Setters (60%) compared to the rest that is truly needed for the logic of the game.

A couple of Google searches have claimed that Getters and Setters are evil, whilst others have claimed that they are necessary for good OO practice and great programs.

What are your opinions on this? Should I be changing my Getters and Setters for my private variables or should I stick with them?

+39  A: 
  • Very evil: public fields.
  • Somewhat evil: Getters and setters where they're not required.
  • Good: Getters and setters only where they're really required - make the type expose "larger" behaviour which happens to use its state, rather than just treating the type as a repository of state to be manipulated by other types.

It really depends on the situation though - sometimes you really do just want a dumb data object.

Jon Skeet
Since it's not obvious that your "somewhat evil" cases won't eventually need a "larger behaviour", i'd go for the "good" way, just in case, so you don't have to change your code everywhere if you change your mind !
Benoît
@Benoît - I think that's the point. Jon is saying that unnecessary getters and setters are barely better than public fields - there are better choices - but they are still better than public fields.
Phil Nash
Each of these values change as the game goes on, so no constants are required. However, these variables are only really used for holding settings for the actual game (i.e. mode, timeLimit). This is why I cannot help but feel that they are somewhat unnecessary.
EnderMB
Let me go a little bit futher. Should the internals of the class use getters/setters instead of directly accessing the fields? My opinion is that yes.
Ionuț G. Stan
@EnderMB: If the variables are meant to be settings, then encapsulate them in a settings class.
Jon Skeet
So, would it be a good idea to create a separate Settings class, extend the Settings to the game, then extend the Game to its sister classes? If I do that am I still able to edit settings from within the sister classes?
EnderMB
No, you don't want Game to extend Settings. Settings serve as a value object... a plain pojo with getters and setters.
tehvan
And as a bi-effect, you can then serialize and dump the settings class to a file, and you have saved your settings :)
Svish
Let me see if I get this: Create a Settings class, put all my settings variables, as well as their getters/setters within this class, then call something like Settings s = new Settings() and then use s.getTimeLimit(). I'm struggling to understand from what I've read about value objects on Google.
EnderMB
That sounds right to me.
James Socol
@tehvan: +1 for "plain pojo" ;-)
Mo
@Mo - There's a lot to be said for a plain old pojo object :)
Daniel Earwicker
Just don't forget to do a YAGNI check when tempted to promote a POJO to a Bean. Accessors, serialization, etc. are a form of complexity: http://stackoverflow.com/questions/601721/decoupling-vs-yagni
Chris Noe
+9  A: 

My opinion is that getters and setters are a requirement for good programs. Stick with them, but don't write unnecessary getters/setters - it's not always necessary to directly deal with all variables.

Joonas Pulakka
A: 

You may want to replace some of your classes by value classes. This will allow you to remove the getter and avoid problems when the content is changed from under you.

David Segonds
+3  A: 

As always the only answer is: it depends. If you are the only peron touching the code, you can do anything you're comfortable with, including taking shortcuts.

One of the benefits of using setters is that checks need to be performed at only one location in your code.

You might want to pay some closer attention to what is actually being get and set by these methods. If you're using them to provide access to constant values you are probably better off by using constants.

Jeroen van Bergen
+1  A: 

If you need external access to individual values of fields, use getters and/ or setters. If not, don't. Never use public fields. It's as simple as that! (Ok, it's never that simple, but it's a good rule of thumb).

In general you should also find that you need to supply a setter much less often than a getter - especially if you are trying to make your objects immutable - which is a Good Thing (but not always the best choice) - but even if not.

Phil Nash
+7  A: 

Your Game class is probably following the god object antipattern if it exposes that many variables. There's nothing wrong with getters and setters (though their verbosity in Java can be a bit annoying); in a well-designed app where each class has a clearly separated functionality, you will not need dozens of them in a single class.

Edit: If the main point for the getters and setters is to "configure" the game classe (I understand your comment that way), then your probably don't need the getters (it's perfectly fine for a class to access its own private variables without using get methods), and you can probably collapse many of the setters into "group setters" that set several variables which belong together conceptually.

Michael Borgwardt
The problem is that whilst there are several settings for this game they are minute in their differences, with only a couple of extra methods typically needing to be applied in the sister classes to provide different values.
EnderMB
Thanks for the reply. In response to your edit, if I call two setters from within every sister class it would be good OO practice to remove both setter methods in the main Game class to turn then into one group setter?
EnderMB
Exactly - if those values are always set together, it's better to convery this information by having only one setter. It would be even better to put them together in a class, if there are more than two, or if there are methods that operate only on them and which could also be put into that class.
Michael Borgwardt
A: 

This depends on the programming language in question. Your question is framed in the context of Java, where it seems that getters and setters are generally thought of as a good thing.

In contrast, in the Python world, they are generally considered as bad style: they add lines to the code without actually adding functionality. When Python programmers need to, they can use metaprogramming to catch getting and/or setting of object attributes.

In Java (at least the version of Java I learned slightly a decade ago), that was not possible. Thus, in Java it is usually best to use getters and setters religiously, so that if you need to, you can override access to the variables.

(This doesn't make Python necessarily better than Java, just different.)

Lars Wirzenius
+2  A: 

The presence of getter and setters tends to indicate (a "smell" if you are into that sort of primary school language) that there is a design problem. Trivial getters and setters are barely distinguishable from public fields. Typically the code operating on the data will be in a different class - poor encapsulation, and what you would expect from programmers not at ease with OO.

In some cases getters and setters are fine. But as a rule a type with both getters and setters indicates design problems. Getters work for immutability; setters work for "tell don't ask". Both immutability and "tell don't ask" are good design choices, so long as they are not applied in an overlapping style.

Tom Hawtin - tackline
Trivial getters/setters have a significant advantage to non-private fields -- their implementations can be changed later without affecting callers. This allows controlled access/mutation where needed.
Scott Stanchfield
It generally doesn't really make any sense to change their implementation.
Tom Hawtin - tackline
A: 

Just FYI: In addition to all the excellent answers in this thread, remember that of all reasons you can come up with for or against getters/setters, performance isn't one (as some might believe). The JVM is smart enough to inline trivial getters/setters (even non-final ones, as long as they aren't actually overridden).

gustafc
+5  A: 

It's a slippery slope.

A simple Transfer object (or Parameter object) may have the sole purpose of holding some fields and providing their values on demand. However, even in that degenerate case one could argue that the object should be immutable -- configured in the constructor and exposing only get... methods.

There's also the case of a class that exposes some "control knobs"; your car radio's UI probably can be understood as exposing something like getVolume, setVolume, getChannel, and setChannel, but its real functionality is receiving signals and emitting sound. But those knobs don't expose much implementation detail; you don't know from those interface features whether the radio is transistors, mostly-software, or vacuum tubes.

The more you begin to think of an object as an active participant in a problem-domain task, the more you'll think in terms of asking it to do something instead of asking it to tell you about its internal state, or asking it for its data so other code can do something with those values.

So... "evil"? Not really. But every time you're inclined to put in a value and expose both get... and set... methods on that value, ask yourself why, and what that object's reponsibility really is. If the only answer you can give yourself is, "To hold this value for me", then maybe something besides OO is going on here.

joel.neely
+42  A: 

There is also the point of view that most of the time, using setters still breaks encapsulation by allowing you to set values that are meaningless. As a very obvious example, if you have a score counter on the game that only ever goes up, instead of

// Game
private int score;
public void setScore(int score) { this.score = score; }
public int getScore() { return score; }
// Usage
game.setScore(game.getScore() + ENEMY_DESTROYED_SCORE);

it should be

// Game
private int score;
public int getScore() { return score; }
public void addScore(int delta) { score += delta; }
// Usage
game.addScore(ENEMY_DESTROYED_SCORE);

This is perhaps a bit of a facile example. What I'm trying to say is that discussing getter/setters vs public fields often obscures bigger problems with objects manipulating each others' internal state in an intimate manner and hence being too closely coupled.

The idea is to make methods that directly do things you want to do. An example would be how to set enemies' "alive" status. You might be tempted to have a setAlive(boolean alive) method. Instead you should have:

private boolean alive = true;
public boolean isAlive() { return alive; }
public void kill() { alive = false; }

The reason for this is that if you change the implementation that things no longer have an "alive" boolean but rather a "hit points" value, you can change that around without breaking the contract of the two methods you wrote earlier:

private int hp; // Set in constructor.
public boolean isAlive() { return hp > 0; } // Same method signature.
public void kill() { hp = 0; } // Same method signature.
public void damage(int damage) { hp -= damage; }
Zarkonnen
what about in a language like c# or actionscript, where get and set are part of syntax? isAlive could just have a getter but not a setter.
Iain
public void addScore(int delta) { score += delta; }I'd prefer unsigned int delta, if its only supposed to increase =)
Viktor Sehr
Fantastic answer. I've read about 5 articles today on the get/set debate but this sums it up really well. Cheers.
jammus
+1  A: 

Use getters and setters, even in the simplest cases. They become your public API, which won't need to change if the internal logic of the getter or setter needs to change. You can't do that with a public field.

Here's a simple example without getters and setters.

class Point
{
    public int x;
    public int y;

    Point(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

Now suppose I use the class as follows.

Point p = new Point(3, 4);
int oldx = p.x;
int oldy = p.y;
p.x = 5;
p.y = 6;

Now all of my client code is tied to the implementation of my class. If I need to change Point to include setters that validate their input, I need to change all of the client code that uses it too.

This is bad enough if I'm using Point in hundreds or thousands of places spread out over a dozen projects. It's a lot worse if I released that class to the public to be used by hundreds or thousands of other developers. It would be easy to change the implementation if I'd used simple getters and setters in the first place. Not a single line of client code would need to change.

Bill the Lizard
The "evil of getters and setters" discussion wasn't about whether you should make fields public or not. It was "tell, don't ask" related. Is it good design to let other objects play with your instance variables?
Terry Wilcox
+4  A: 

You've already had a lot of good answers on this, so I'll just give my two cents. Getters and setters are very, very evil. They essentially let you pretend to hide your object's internals when most of the time all you've done is tossed in redundant code that does nothing to hide internal state. For a simple POJO, there's no reason why getName() and setName() can't be replaced with obj.name = "Tom".

If the method call merely replaces assignment, then all you've gained by preferring the method call is code bloat. Unfortunately, the language has enshrined the use of getters and setters in the JavaBeans specification, so Java programmers are forced to use them, even when doing so makes no sense whatsoever.

Fortunately, Eclipse (and probably other IDEs as well) lets you automatically generate them. And for a fun project, I once built a code-generator for them in XSLT. But if there's one thing I'd get rid of in Java, its the over-dependence on getters and setters.

rtperson
You left out the reason why they're evil.
Bill the Lizard
I fixed it so my objection is clearer.
rtperson
+6  A: 

Getters and setters enforce the concept of encapsulation in object-oriented programming.

By having the states of the object hidden from the outside world, the object is truly in charge of itself, and cannot be altered in ways that aren't intended. The only ways the object can be manipulated are through exposed public methods, such as getters and setters.

There are a few advantages for having getters and setters:

1. Allowing future changes without modification to code that uses the modified class.

One of the big advantage of using a getter and setter is that once the public methods are defined and there comes a time when the underlying implementation needs to be changed (e.g. finding a bug that needs to be fixed, using a different algorithm for improving performance, etc.), by having the getters and setters be the only way to manipulate the object, it will allow existing code to not break, and work as expected even after the change.

For example, let's say there's a setValue method which sets the value private variable in an object:

public void setValue(int value)
{
    this.value = value;
}

But then, there was a new requirement which needed to keep track of the number of times value was changed. With the setter in place, the change is fairly trivial:

public void setValue(int value)
{
    this.value = value;
    count++;
}

If the value field were public, there is no easy way to come back later and add a counter that keeps track of the number of times the value was changed. Therefore, having getters and setters are one way to "future-proof" the class for changes which may come later.

2. Enforcing the means by which the object can be manipulated.

Another way getters and setters come in handy is to enforce the ways the object can be manipulated, therefore, the object is in control of its own state. With public variables of an object exposed, it can easily be corrupted.

For example, an ImmutableArray object contains an int array called myArray. If the array were a public field, it just won't be immutable:

ImmutableArray a = new ImmutableArray();
int[] b = a.myArray;
b[0] = 10;      // Oops, the ImmutableArray a's contents have been changed.

To implement a truly immutable array, a getter for the array (getArray method) should be written so it returns a copy of its array:

public int[] getArray()
{
    return myArray.clone();
}

And even if the following occurs:

ImmutableArray a = new ImmutableArray();
int[] b = a.getArray();
b[0] = 10;      // No problem, only the copy of the array is affected.

The ImmutableArray is indeed immutable. Exposing the variables of an object will allow it to be manipulated in ways which aren't intended, but only exposing certain ways (getters and setters), the object can be manipulated in intended ways.

I suppose having getters and setters would be more important for classes which are part of an API that is going to be used by others, as it allows keeping the API intact and unchanged while allowing changes in the underlying implementation.

With all the advantages of getters and setters said, if the getter is merely returning the value of the private variable and the setter is merely accepting a value and assigning it to a private variable, it seems the getters and setter are just extraneous and really a waste. If the class is going to be just for internal use by an application that is not going to be used by others, using getters and setters extensively may not be as important as when writing a public API.

coobird
A: 

I've been programming in java for few monts ago, and I've learned that we should use getters & setters only when it's necessary for the application

have fun :)

Giancarlo
What if your object changes so that one field needs a getter and a setter? If that field is being used in 100 different places, that's 100 different changes you need to make. If you use getters and setters from the start you only need to change it in one place, the object that's changing.
Bill the Lizard
If you need to expose that variable to 100 different places, use a getter and setter. But is it really good OO practice to have 100 different places playing with your object's internal data?
Terry Wilcox
@Terry: That object could be used in 100 different projects, not just called in 100 different places in one project.
Bill the Lizard
...also, I should be saying "class" instead of "object".
Bill the Lizard
A: 

A pretty good article on the subject from JavaWorld:

More on getters and setters by Allen Holub.

js