Is it in an anti-pattern to always use get and set

2019-01-20 09:44发布

问题:

This question already has an answer here:

  • Using getters within class methods 5 answers

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?

回答1:

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.



回答2:

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.



回答3:

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.



回答4:

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.



回答5:

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



回答6:

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.



回答7:

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.



回答8:

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.



回答9:

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


回答10:

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.)



回答11:

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.