Win a copy of The Little Book of Impediments (e-book only) this week in the Agile and Other Processes forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Encapsulation for Reference Variables

 
Brian Brumpton
Ranch Hand
Posts: 40
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hey All,

I'm working through Chapter 5 of the K&B study guide and the last section of the chapter is Encapsulation for Reference Variables.

You're given the following coding example:

On page 295, in the 2nd paragraph, it says:

"For the purposes of the OCA exam, the key point is this: When encapsulating a mutable object like a StringBuilder, or an array, or an ArrayList, if you want to let outside classes have a copy of the object, you must actually copy the object and return a reference variable to the object that is a copy."

However, there is no example of how this code should look. Then, in the Self Test section question 12 asks the following:

Given:

Which lines of code (if any) break encapsulation? (Choose all that apply.)
A. Line 3
B. Line 4
c. Line 5
D. Line 7
E. Line 8
F. Line 9
G. The class is already well encapsulated

I believe this question is directly related to the section above, however, it uses an ArrayList instead of a StringBuilder. I feel as if I don't know how to code it properly, I'm not likely to spot the answer on the exam. How would you properly encapsulate either of these?

 
Roel De Nijs
Sheriff
Posts: 10662
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Brian Brumpton wrote:I believe this question is directly related to the section above, however, it uses an ArrayList instead of a StringBuilder. I feel as if I don't know how to code it properly, I'm not likely to spot the answer on the exam. How would you properly encapsulate either of these?

You are correct! The question is completely related to the section above.

As you know, encapsulation is the technique of making the fields in a class private and providing access to the fields via public methods. So with primitives that's pretty straightforward. You make the field private, add a getter and/or setter for this field and your class is well encapsulated as shown in this example:You can only retrieve and update the age field using the appropriate method.

But when mutable objects are involved, it get's a lot trickier. Let's assume we want to create a class which holds a list of persons. When a person is added to the list, the person's age is added to the sum. And you also can retrieve the list and the sum of all ages. So the code would look like this (which is similar with the Fortress class):On first glance, this seems well-encapsulated code, but it is not! The get method breaks the encapsulation. Why? Because the get method returns list (the private data member). So the private data member is exposed outside the class and you can add elements to a PersonCollection instance without using the add method (and thus the total age will be incorrect). Illustrated in this code snippet:You expect this code to print 1, because you invoked the add method (of PersonCollection) once. But the code will print 2.

How can you properly encapsulate the PersonCollection class (applies also to the Special and Fortress classes)? It's extremely easy, no rocket science at all: just create a copy of the private data member you are returning, so you are not exposing the private data member but a copy. So the new and improved version of the get method of the PersonCollection class looks like:With this little change it's impossible to add persons to the private data member list, unless you use the add method (which was added specifically for this purpose). With this new version of the get method, the PersonCollection is well-encapsulated as well.
If you now run the previous code snippet, the code will print 1 (which is the expected value).

For the Special class, you'll need to change the getName method to:Again creating and exposing a copy of the private data member (instead of the data member itself).

And what do you think about this code? Well-encapsulated or not (and why)?

Hope it helps!
Kind regards,
Roel
 
Brian Brumpton
Ranch Hand
Posts: 40
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Roel,

And what do you think about this code? Well-encapsulated or not (and why)?



I have played with the code you're asking about and my answer would yes, it's well-encapsulated, however, the paranoid OCA aspirant in me says there's a trick hiding here.

First, I noticed that you had two getAge() and setAge() methods which would fail to compile. I don't believe that was the intent of your question(that would be way too easy ).

With what I believe to be the corrected code:

It's lines 3 and 6 that jump out at me as the questionable ones. I wrote the following to test it:
However, based on the response you provided this also compiles:

Which leaves open the possibility, in my mind, that it may not be well encapsulated and it's my test code that is not accurate.

Thanks,

Brian


 
Roel De Nijs
Sheriff
Posts: 10662
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Brian Brumpton wrote:I have played with the code you're asking about and my answer would yes, it's well-encapsulated, however, the paranoid OCA aspirant in me says there's a trick hiding here.

Being a little bit paranoid on the exam is definitely not a bad thing. My rule of thumb: if it looks too easy, there's probably a catch

Brian Brumpton wrote:First, I noticed that you had two getAge() and setAge() methods which would fail to compile. I don't believe that was the intent of your question(that would be way too easy ).

You are correct! That was a blatant copy/paste error of me. Sorry about that! (In my defense: I didn't use an IDE to create these code snippets, just entered them in the reply textarea )

Just for the record: only the 2 getAge methods result in a compiler error. Nothing wrong with the 2 setAge methods. That's a valid overload: 1 method takes a String and the other an Integer.

Brian Brumpton wrote:It's lines 3 and 6 that jump out at me as the questionable ones. I wrote the following to test it:

Your test code doesn't actually test if the Employee class is well-encapsulated. As you (probably) noticed in my example code, I used 1 instance of the PersonCollection class to verify if this class is well-encapsulated. Your code checks if age is an instance or class variable. Each instance clearly has its own value for the age variable, so age is definitely an instance variable. If emp2.getAge() would print 35 as well, age would be a class variable.

Let me not spoil your fun and take the PersonCollection example to explain what you need to test/check to ensure 100% encapsulation of (reference) variables. First the general rule: In every class you have accessor and mutator methods. A class is well-encapsulated if your private data members can only be retrieved and changed using these accessor and mutator methods. If you can access/change a private data member without using the accessor and mutator methods, your class is not well-encapsulated.
Now let's apply this rule to the PersonCollection example:
  • accessors: get() and getTotalAge()
  • mutators: add(Person p)
  • In the code snippet you can clearly see, I could change the private data member list without using the mutator method (using persons.get().add(p2);). So PersonCollection is not well-encapsulated. After applying the fix (return new ArrayList<>(list);), I can only change the private data member list using the mutator method => PersonCollection is well-encapsulated.

    Brian Brumpton wrote:Which leaves open the possibility, in my mind, that it may not be well encapsulated and it's my test code that is not accurate.

    Now it's again up to you I provided a little bit extra knowledge. Try to apply to this (adjusted) code snippet:

    Hope it helps!
    Kind regards,
    Roel
     
    Brian Brumpton
    Ranch Hand
    Posts: 40
    1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Roel,

    I didn't want to go to sleep, knowing I would be up in middle of the night, if I didn't find an answer. Now, after giving up, and heading off to bed here I am at 2AM working on it again.

    After giving up, I came back to the API and noticed that, in my haste to find a suitable method (as they use in the Special example with the StringBuilder class), I had skipped over the fact that the Integer class is immutable.


    So I maintain my original answer that yes, it is well encapsulated because there are no mutable objects involved.

     
    Guillermo Ishi
    Ranch Hand
    Posts: 789
    C++ Linux Python
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    I seem to remember something similar but less obvious, sort of a classic example that originally turned up as somebody's exploit.
     
    Roel De Nijs
    Sheriff
    Posts: 10662
    144
    AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Brian Brumpton wrote:I didn't want to go to sleep, knowing I would be up in middle of the night, if I didn't find an answer. Now, after giving up, and heading off to bed here I am at 2AM working on it again.

    I know that feeling. At university I spent many, many nightly hours to fix some coding issue. And going to bed to sleep before it was fixed, wasn't an option because i knew I would be pondering all night

    Brian Brumpton wrote:So I maintain my original answer that yes, it is well encapsulated because there are no mutable objects involved.

    Spot-on!

    Both String and Integer are immutable, so the class is well encapsulated. You only have to worry if your instance members are mutable.
     
    • Post Reply
    • Bookmark Topic Watch Topic
    • New Topic