views:

546

answers:

12

In Java classes is it considered good or bad practice to access member fields with their getters and setters?

e.g which is better:

public Order {
    private Agreement agreement;

    public Agreement getAgreement() {
    return agreement;
    } 

    public void process() {
       //should I use:
       getAgreement().doSomething();
       //Or:
       agreement.doSomething();
    }
}

In general I think accessing the field directly is best due to the KISS principle and also someone may override the get method later with unpredictable results.

However my colleagues argue that it is better to keep a layer of abstraction. Is there any consensus on this?

+6  A: 

I think that the public interface of a class represents encapsulation around state and as such even the other workings of the class benefit from that encapsulation.

If you have wrapped a field in a public get method then there is a reason you have done so. Perhaps there is logic within that method to lazy-load the field, or provide an audit trail. Whatever the reason for the method, your class will most likely need that logic as well.

Andrew Hare
I've seen specific problems with this when using Hibernate for ORM. Code that was using the variables directly was always getting null values, code that used the getters always worked. Hibernate was supplying a proxy class to support lazy loading.
John Meagher
John, wouldn't that problem only arise if you have the hibernate annotations on the getter/setter? I put the annotations on the class's field and the hibernate docs say that causes it to manipulate the field directly. Doing that also allows you to provide getters without setters since hibernate isn't using them.
lumpynose
@lumpynose: I believe hibernates use of field or property based access is orthogonal to whether it generates proxy classes for lazy loading. Hibernate can still use field level access and require proxies to implement the lazy load functionality, triggering the NPEs you get if lazy loading isn't properly executed on field access.
Jherico
@lumpynose I forget how it was setup, the annotations may have been on the getters. It was also using JPA rather than Hibernate directly, so that may have changed things. My points stands though, unless you declare your class as final then you need to think about what will happen if someone overrides one of your public methods.
John Meagher
A: 

In order for it to be an anti-pattern, it'd have to be decidedly harmful. I don't see how there can possibly be any harm in defining getters and setters. At most, it is a waste of time (and typing), which makes it pointless, but not an antipattern.

jalf
It destroys encapsulation.
Tom Hawtin - tackline
+2  A: 

Keeping a layer of Abstraction is a good thing in Java.

The problem is that all the code that directly accesses your member variables without the class noticing it isn't under the control of your class.

So the moment you decide to edit your class in a way that one member that is used in a division as an example should never be 0 you have to be able to ensure that this value is only changed in a way that ensures this. So you would add a setter for this method and change the member to private. But now you need to change all the code that is accessing the member without the setter.
If you know you are changing the value from outside the class and only then provide a setter if you don't know make the variable private and if you need access later maybe provide a getter or a setter.

It gets an Anti-Pattern if there are certain methods in other objects that are always using get for a member then performs some calculations and then uses get. This shows that either the member should be in the other class or that the method needs to be in this class.

Having a getter and a setter without thinking about it for every member breaks encapsulation and is not a good design choice. For mor insides read this article

Janusz
+7  A: 

Honestly, in my opinion, it depends on what you're using it for. Personally, when in doubt, I always leave that extra level of abstraction in there just in case I need to override it later in a subclass. Many times have I been saved from the pain of rewriting a class just because I left a getter or a setter open to overriding.

Another thing is that other clients/programmers might need to use your class in a way that you haven't yet thought of, for example, pulling the Agreement class out of a database. In that case, when they override your class, you have made it painless for them (or potentially a future you) to modify how that data is retrieved.

So unless you're absolutely certain that there is only one way to access that field, and that it's 100% direct, it's probably best to decouple the retrieval and modification of values so that at some future point you can save yourself from rewrite hardship.

Zachary Murray
A: 

It depends on what you use your getters and setters for. Generally I use them when I need to sanity check data coming into a class or format data going out. In that respect, I really use getters and setters as an interface layer between this class and other classes that might need access to its data.

I tend to write my internal code such that it knows how to handle data private to this class, so accessing it with its own getters and setters is generally unnecessary and undesired.

It all depends on how you use your getters and setters, though.

Bob Somers
A: 

My rule of thumb is that if they do anything more complex than just set or return the value, use the setters/getters. Otherwise, it's not needed since you can fix any problems caused by changes to the member variables.

patros
But the reason for consistently using the getter and setter is that while the getter/setter may do nothing but get and set the value *today*, that may not be true tomorrow.
nsayer
+1  A: 

I'm now working on something that makes me in favor of the getters: we're now moving part of our properties into a "property bag", which means you cannot just reference the variable. So in addition of changing the getter, we need to change all the places that reference that variable. It's something to keep in mind.

Tamar
Now I would call a property bag an anti-pattern. It brings to mind a map of name value pairs where the values are untyped. Its a lazy alternative to actually having class design and it can bite you in the ass.
Jherico
In general, yes, it is better to store the data in variables. The reason we are now converting is because we are transferring our application to use the BlackBerry persistent store. When using the persistent store every change to the object structure (adding another int variable) will corrupt the persisted data. There are other solutions, but we found a property bag to be the best fit for us. In any case, this is just an example of a situation when variable access way changes.
Tamar
+5  A: 

The core issue here is that direct field access is ineligible for interception by subclass overridden methods, AOP, dynamic proxies and the like. This can be a good or bad thing depending on the case. I would say that using getters and setters internally is not an anti-pattern or a pattern. It is a good or bad thing depending on the situation, and the design of your class.

Jherico
A: 

You're right in that it's annoying to do all that extra work for every attribute variable. Why does the language allow something so basic that no one does? There are very compelling reasons for not allowing direct attribute access, however.

I prefer Eiffel's Unified Access Principle. You can never assign to an attribute, and attributes and functions are accessed in the same way:

class EXAMPLE
feature
  variable: INTEGER
  variable_function: INTEGER
    do
      result := 4
    end
  variable_two: INTEGER assign variable_assign
  variable_assign (in: INTEGER)
    do
      variable_two := in
    end  
end

feature
test
local
  test: EXAMPLE
  value: INTEGER
do
  create test
  value := test.variable  -- Valid
  value := test.variable_function  -- Valid and same even though it's a function
  test.variable := value -- Invalid
  test.variable_two := value -- Valid, an explicit setter is defined
end
+3  A: 

It sounds to me like some people are interpreting this question as being about getters and setters that are used externally; my interpretation of Pablojim's question was that it's about using them within the class, as opposed to the class directly accessing its fields. (Which are private.)

In that light, I'm with Jherico and patros; use direct access from within the class unless there's some reason not to.

lumpynose
Problem is, the "reason not to" might belong to some other developer using your library, at some time and place far distant. They override the accessor and the class doesn't work properly. Bypassing a non-final accessor is a bug.
erickson
True. I guess I don't worry about it so much because I automatically add a final to my class declaration. I'm of the religion that if a class doesn't have the final modifier on it that it should be an abstract class; it was designed from the start to be subclassed. Of course, there's that problem of proxying and wanting a non-final class and I perhaps the no-arg constructor added mess.
lumpynose
A: 

I think this is something that needs to be considered on a case by case basis. Using a getter throughout your class code does complicate it, and probably makes it slightly slower. However, it also makes it more extensible and reusable.

What I've usually done is use the getter if I can forsee any reason someone might want to override my getter with another one. If it's something so basic and simple that it would never make sense, I generally don't use getters.

If you write your code to access the variables without the getter, consider making the getter function "final". That way, no one will try to override your code and tear his hair out wondering why it's not working. (Note that Spring and Hibernate proxies might make this a bad idea.)

Grimarr
A: 

In your example:

  • The getter is public, so any client can call it.
  • The getter is not final, so any subclass can override it.
  • The class is neither final nor abstract
  • The class does not implement any interfaces.

It seems to me that your class is already broken. How you access that one field is not going to make much difference.

Why is it broken? Because you have a public getter that probably has no reason to be there (otherwise one of the 4 points above would apply.)

finnw