Win a copy of Java 9 Modularity: Patterns and Practices for Developing Maintainable Applications this week in the Java 9 forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

Using Getters and Setters  RSS feed

 
Rachel Rosemond
Greenhorn
Posts: 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
While browsing Software Enginnering Stack Exchange, I've come across posts that suggest the use of getters should be avoided. The suggested alternative, to me anyways, seems to violate the SRP, by allowing your class to be aware of UI/display code. Here an example of the posts I'm talking about: Encapsulation and Displaying Information

or the accepted answer to this question: Encapsulation and Getters

The accepted answer to this question is what I have in mind and agree with: Avoid getters and setters, displaying user informations

Once your not using the getters to gather information and do a calculation or implement a behavior that should be inside the class, using a getter is fine. As eloquently stated by Junilu Lacar in this post: Encapsulation and GUI

Yes, the idea I explain in the other thread is about getters breaking encapsulation when an external calculation that uses raw information you obtain via the getter is made. This moves logic that should be inside the object elsewhere outside of it. Displaying information about an object obtained via a getter is not the same. You are not performing calculations with the information and externalizing logic that should be in the object being examined. In this way, the use of getters is fine and it doesn't break encapsulation.

I guess breaking encapsulation only happens when the information you take from the object also involves taking away the responsibility of interpreting that information from said object.


But there are posts on other sites, like the ones above that seem to refute even using getters for display. Instead they seem to suggest ideas like returning an array or Map collection of the data. This seems unnecessary and a lot of work for the simple task of displaying.

Another thing is, suppose you wanted to use a design pattern, for example, the Visitor pattern. This pattern breaks the guideline that you shouldn't use the getters to gather data and preform a calculation that should be done inside the class. Quote from Dzone:

What the Visitor pattern actually does is create an external class that uses data in the other classes. If you need to perform operations across a dispate set of objects, Visitor might be the pattern for you.


Even in Effective Java states:
Provide programmatic access to all the information contained in the value returned by the toString()


I often see the following statements, but I don't know to threat them.

  • Avoid Getters, they're evil. If your providing a getter for every field, you're doing something wrong and you need to rethink your design.


  • Another issue is I often here the phrase,  Tell, don't ask. Fine, but what about objects where that's impossible? For example, suppose I have a Book object, my object will obviously have a title and a list containing all the authors.  If I wanted to display this in a UI, I would implement and call the getters. I can't tell a Book, "Hey, book, what's your title?" A person reads title off of the Book. I could have a method called readTitle(), but that's just a getter without really calling it a getter. A person, can jump to the end and determine the number of pages of the book. Now, if I've read a few of the pages and wanted to know how many I have left, then I would write an internal method called numberofpagesleft(int pagesread) and do my calculation and return the result.
  •   

    Questions:

    1. How should I threat what theses developers are saying? do I take what they say as rules set in stone? Or threat them as guidelines? be aware of them, try to use them, but if after you thought if over, and you have to go against one of these guidelines, do it, if and only if, it makes sense?

    2. How do I silence the voice that bothers me everytime I write a getter for display that says, "You're doing something wrong" but the thing is what should I do? The alternative violates SRP and causes more problems. What's even more interesting is, those same developers that say Getters are evil and should be avoided, they have to sometimes implement them when using Compartor, and they justify it by twisting there defination about getters. Like so:Does the use of Comparator interface breaks encapsulation in Java?

    Taking my Book example and display for UI, I would provide a getter of all three fields(Title, List of Authors, and Number of Pages), because that's what represents my Book object and is returned in the toString(). Now how do I come to terms with those developers that believe I'm breaking encapsulation by providing getters for every field, without violating the SRP?
     
    Campbell Ritchie
    Marshal
    Posts: 56193
    171
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Welcome to the Ranch

    You appear to have done lots of reading (), but is our opinion any more definitive than anybody else's?

    Take a real‑world example. I often think there are things about me which are “public” which anybody is allowed to access, for example looking at my face (they don't usually do that twice). Three are things package‑private which I only allow one other person access to, and there are things private which even I would prefer not to have access to If you make all your fields private, then you can consider what sort of information can be passed on to other codeYou don't want the naughty thought shown to anybody else under any circumstances, but you can't do any harm with the first name. And there is another reason about first name (if it is a String): when you go through Effective Java next time, look for the chapter about defensive copies. String is immutable, so you cannot mess up the innards of the object by returning it. You might mess up the object however, if you keep your names as an array, you can do all sorts of harm by returning that array unchanged:-Create a class Person like that with a name array and see how you can get it to go wrong with that getName method. I think that experience will tell you more about breaching encapsulation than any number of forum posts. And I am stopping now; I'll let somebody else say soemthing.
     
    Rachel Rosemond
    Greenhorn
    Posts: 2
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Take a real‑world example. I often think there are things about me which are “public” which anybody is allowed to access, for example looking at my face (they don't usually do that twice).


    Don't be hard on yourself


    When you go through Effective Java next time, look for the chapter about defensive copies. String is immutable, so you cannot mess up the innards of the object by returning it.


    I favor immutable classes and well aware of now to make immutable copies Effective Java is indeed a good resource.

    My problem lies with the many definitions about what breaks in encapsulation. Some say simply providing getters breaks encapsulation, while some say as long as it's not for every field, it's okay.

    In Effective Java, it says to provide access to all the individual elements return by the toString()(Not actual quote, but all those lines).

    Suppose following that guideline from Effective Java, I have to provide getters for all the fields(My Book example), what then?

    My whole problem is, I stand behind the definition that, even if you provide getters for all the fields because that's what's returned in the toString(), as long as you're not implemeting a behaviour or calculation outside the class by calling getters, then it's fine. BUT, there is that voice that always says, IT WRONG. This is where I get discourged, and don't really know what to do. I don't have years of experience, or a CS degree, and I'm in no position to refute any statement about encapsulation. Why can't there be a solid definition about what breaks encapsulation and what doesn't?  
     
    Junilu Lacar
    Sheriff
    Posts: 11428
    173
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Rachel Rosemond wrote:This seems unnecessary and a lot of work for the simple task of displaying.

    That's one of the biggest trade-offs with "purity" of OO design, the convenience and simplicity of allowing the use of getters for display purposes. Yes, we want to make sure that our objects don't inadvertently give away too much control over their properties but at the same time, it can get onerous and tedious if we keep everything locked down and hidden away.

    There are no hard and fast rules and I think you really need to consider each case based on its own merits. A few things that I would factor into consideration: the impact of loosening up restrictions, the potential risks involved, and the cost in time and effort to mitigate those risks. Kind of the same triangle you have for addressing security concerns, really.
     
    Junilu Lacar
    Sheriff
    Posts: 11428
    173
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Rachel Rosemond wrote:My problem lies with the many definitions about what breaks in encapsulation.

    In practical terms, I consider encapsulation to be broken if my object's property can be changed directly by some external entity without my object's direct involvement or knowledge. When dealing with primitives, this isn't too much of a concern. When dealing with immutable properties, not too much of a concern either. It's when I'm handing out direct references to mutable objects that I really pay attention because once that's out there, the internal state of my object could change in unexpected ways, especially when concurrency gets into the picture. You've already mentioned defensive copies as a strategy to mitigate the risk. A Transfer Object is another one.

    There's another approach, one that I don't know if there's a pattern already defined. Let's call it the Trusted Delegate/Emissary for now. This is where you have another class that serves as a go-between. This may sound like a Transfer Object but it's a little smarter. You can let the Trusted Delegate have intimate knowledge about your properties and you trust that he will take care of those properties and either inform you in a timely manner about changes that concern you or they do all the responsible things like making defensive copies for you.

    So, if you don't like having a JComponent inside your Domain object, then you can create a TrustedDelegate that has some privileged intimacy with your Domain object but can deal with all the UI-related things that you don't want muddying up your Domain logic. Yes, it's another layer of abstraction but sometimes there's value to separating the UI-related responsibility out to a delegate.

    This may sound like a Proxy pattern but the motivation is different. It also might sound like a Decorator and I guess it has some similarities but again, the motivation is different. It's more like it's a View-related object that has special privileges to be intimately acquainted with a Domain object. Its responsibility is to safely provide domain object information for display purposes while safeguarding the domain object's encapsulation. Another way I like to look at this is like it's a DMZ for my domain object's sensitive mutable properties.
     
    Tim Holloway
    Bartender
    Posts: 18774
    74
    Android Eclipse IDE Linux
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Java has sometimes been criticized for over-abstraction, but the JavaBean approach does expect that the beans should be "black boxes" and by implication, that the properties within not be directly accessible.

    There are some good reasons for this. First and foremost, it insulates the bean client from internal changes to a property. For example, what started out as "employee.salary" might prove better as employee.financial_info.salary". Or the data type might change. I used to use Hungarian Notation back in my C++ days and I cannot count how many times a property shifted from boolean to enumerated or something like that. In that particular case, that meant either renaming the property or having misleading code.

    Another good reason is that sometimes its useful to monitor property access. Modern IDEs can often breakpoint variable value changes, but older/more primitive IDEs often could only breakpoint code, so the only way to catch changes or find unexpected reads was to use get/set methods and breakpoint them. And what about where there isn't an IDE to be found - like in production? You can add logging statements to get and set methods and even capture and log stack backtraces.

    Then there are side effects. Ideally property access methods are idempotent - meaning that the same thing happens the 100th time as happened the first time you invoked them. But that's at the abstract level. One of my favorite JSF tricks is to have a "get" method constuct and cache the value of the returned property on the first call - a very useful thing to do when you're having to pull from a high-overhead resource (such as a database) and you KNOW that multiple calls will be made (JSF can invoke get/set methods easily 5 or 6 times for a single web page request). You cannot do that kind of magic with direct property access and I definitely don't recommend mixing direct and get/set accessors in a single bean.

    The cases against get/set methods are things like these:

    A) There's extra overhead when doing a method call versus direct access. (Don't count on it - the Java runtime will optimize the call internally to direct access when it's appropriate)

    B) It's extra work to write get/set methods. (Depends on your development tools. In Eclipse, I can click on a member variable, press a hotkey and the accessors are automatically generated.

    C) It blurs the lines between active code and data access. Yes, but if you're into abstraction, that's not such a bad thing. It makes everything consistent and it makes things flexible.

    Regardless, it's up to you. In some cases, such as the Java Persistence Architecture (JPA), you can select field-type (direct) or method-type (get/set) access for Entity Model Objects. Just don't expect to be able to mix the two.
     
    Junilu Lacar
    Sheriff
    Posts: 11428
    173
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    See this thread: https://coderanch.com/t/686059/Wanna-learn-Method-References#3220767 for another reason you might want to provide a getter for use by a closely related class.

    Sometimes you may feel that it's not very appropriate to codify certain business rules in your main domain model object. In the other thread, the example I gave shows an Employee class with a getYears() method and an EmployeeSeniorityRule that encapsulates a very specific rule for determining seniority based on the number of years of service. You might have a similar motivation for separating logic for things like PensionEligibilityRule or SabbaticalEligibilityRule or LoyalEmployeeRecognitionRule.
     
    Tim Holloway
    Bartender
    Posts: 18774
    74
    Android Eclipse IDE Linux
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Interesting.

    I have a misgiving about using method names like "senior" and "junior" in place of isSenior and isJunior, though. You can argue that "is" or "get" should be reserved for actual property accessor methods and I won't disagree, but personally, I prefer test and extraction methods to also employ such naming. It's more grammatical and it is also more indicative of the semantics. It does perhaps fuzz the distinction between such functions and true accesors, but that's preferable to the alternatives - for example, accessor methods could have been called "injectXXX" and "returnXXX/affirmXXX", but that's rather awkward considering their frequency of use.
     
    Junilu Lacar
    Sheriff
    Posts: 11428
    173
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Having said that, of course, there is a way to separate certain responsibilities and still preserve encapsulation by not providing a getter.

    The scheme is somewhat circuitous and illustrates the increased complexity involved in trying to preserve encapsulation. It's a little tedious and you really need to have a good reason to justify the effort you put into writing and maintaining this kind of design to preserve encapsulation.

    You can this code in action here: https://repl.it/NADB/6 (I'll explain it in a followup post)



     
    Junilu Lacar
    Sheriff
    Posts: 11428
    173
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    I experimented with extending the example I gave above and found that due to type erasure rules and generics, it appears that what I wrote is not at all extensible. I'll try to rework it so it's more extensible.

    Back to the drawing board...
     
    Junilu Lacar
    Sheriff
    Posts: 11428
    173
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    I pivoted and reworked my example code a little bit to this: https://repl.it/NADB/9 -- I still haven't figured out if there's a way to eliminate getters and make the code in the previous example more extensible.

    Basically, the approach involves assigning package private visibility to fields. This allows classes in the same package to directly access the fields. CAVEAT: This can get quite dangerous, especially when you have undisciplined developers or developers who don't understand the original motivations. Developer documentation/comments are important here. Anyway, assuming a disciplined developer team, you can keep the consequences of breaking encapsulation under control by providing package private access instead of public getters. I'm sure there would be some interesting discussion about the pros and cons of this approach if you have "OO purists" on your team.  In this case, I didn't see much difference in providing getters with package private access vs. giving package private access to the field values directly.

    The resulting high-level code that you can write, however, seems quite clean and clear to me:


     
    • Post Reply Bookmark Topic Watch Topic
    • New Topic
    Boost this thread!