I feel like I am missing something obvious here, but I am perplexed. Most all sources recommend that, when designing a class, all data members should be private, accessible only via methods of that class. One of the justifications for doing this is to ensure that the nature of those variables is irrelevant outside the object. This means that you can change how the data is stored without requiring code which uses the class to be rewritten. Now say, for a simple example, that you are working with a microscope. One of the data members of your class holds the current position of the focus axis. Obviously, as you are focusing, this value will change frequently. So you will provide a getFocusAxisPosition() method. Here is the part I don't understand. Say that when you started you declared the focusAxisPosition to be an integer. Later hardware improvements allowed more precision and so you changed the internal representation of focusAxisPosition to be a float. Now, doesn't the definition of method getFocusAxisPosition() have to change to reflect the new return type and don't all methods which call this method also have to change? Please forgive me if I have missed something silly or obvious. It certainly feels that way. Any insight would be greatly appreciated. Thanks. Stephanie
Look at it the other way around. Say you'd exported the instance variable, and it changed from an int to a float. Suddenly, everything stops working. If you used accessors, then you could have two of them: the old getAxisPosition that returned an int still (presumably rounding intelligently). Then you write the new interface, getAxisPositionFloat (gotta love the fact that you can't overload based on return type, eh), and you can gradulally switch your code over to using it. Which way is more flexible?
Dave Thomas <br />Author of "<a href="http://www.amazon.com/exec/obidos/ASIN/020161622X/ref=ase_electricporkchop/002-7467239-7061602" target="_blank" rel="nofollow">The Pragmatic Programmer: From Journeyman to Master</a>
Stephanie, This is a great question.I like all the questions which are linked to encapsulation, OO, information hiding.You can find a very intersting thread posted by Junilu Lacar on this.It is named as "Decoupling and Law of Demeter". As regards your question, to make it short and sweet, we should strive to see that the getter methods that we provide do not expose the internal representation to the client.Your method should be such that the client never knows about focusAxisPosition as the internal representation of the Microscope object.The getters like getFocusAxisPosition(), should be avoided, or should be implemented in a way, the client finds it more meaningful - It could be something like this :
Using the above method you have not exposed the internal representation (how exactly it is stored) to the client. Hope this helps, Sandeep
<b>Sandeep</b> <br /> <br /><b>Sun Certified Programmer for Java 2 Platform</b><br /> <br /><b>Oracle Certified Solution Developer - JDeveloper</b><br /><b>-- Oracle JDeveloper Rel. 3.0 - Develop Database Applications with Java </b><br /><b>-- Object-Oriented Analysis and Design with UML</b><br /> <br /><b>Oracle Certified Enterprise Developer - Oracle Internet Platform</b><br /><b>-- Enterprise Connectivity with J2EE </b><br /><b>-- Enterprise Development on the Oracle Internet Platform </b>
Originally posted by Dave Thomas: If you used accessors, then you could have two of them: the old getAxisPosition that returned an int still (presumably rounding intelligently). Then you write the new interface, getAxisPositionFloat (gotta love the fact that you can't overload based on return type, eh), and you can gradulally switch your code over to using it. Dave
Good point Dave. What I often tell people I train in OO is that it "does no worse." Even if you did have to have rewrite all the methods signatures, that's no different than if you had to change the variable, so you're no worse off. And as Dave cleverly pointed out, you can often do better. --Mark email@example.com
Joined: Jun 14, 2000
Thanks to all for your responses! Sandeep, Your link to the thread by Junilu Lacar was especially helpful, as that thread and the article it refered to best addressed the real intent of my question. It seems what I need to consider more when designing the class is "Why does the client need this information?" and "How will they use it?" as opposed to being so focused on actual data types. Thanks again! Stephanie
Joined: Apr 02, 2001
Stephanie, It is so nice to hear you are getting it right.Junilu and myself were brainstorming on this for quite a while.Eventually we saught the help of Dave who finally helped us settle this with very good reasoning.Thanks a lot,Dave Regards, Sandeep [This message has been edited by Desai Sandeep (edited May 24, 2001).]
It seems what I need to consider more when designing the class is "Why does the client need this information?" and "How will they use it?" as opposed to being so focused on actual data types.
One word of caution I might add though is that you probably don't want to go to the trouble of role-reversal (ask not for information you need to do a job; rather, ask he who has the information to do the job for you) if it's a trivial part of the system that is not likely to change since this does add a bit of complexity into your code. You also want to do this early on while refactoring does not entail extensive overhaul. Another approach would be to not have getters return primitive types but rather objects or interfaces. This kind of follows the principle of OO design that states "Program to abstractions rather than concretions." (I forget the name of the principle but you can look it up in an article on Robert Martin's website). Following this principle, you could have your getter return a Number instead of an int. Then you wouldn't even have to overload the method, just go around and change intValue() to doubleValue(). Edit: Sorry, just realized that Number is an abstract class so you would still have to cast the result. Anyway, the point is, if you returned an object or interface that abstracted the notion of a value such that you were insulated from the actual implementation, you'd be much better off than if you returned a primitive type. Junilu
[This message has been edited by JUNILU LACAR (edited May 24, 2001).]
Stephanie, Consider looking at the Microscope problem from a different perspective.Say when you ask the client "Why does the client need this information?".The Client says "I need to get the value to the nearest precision inorder to process further". So what do we do in this case?We are left with no option but to give the focusAxisPosition value to the client.Also, we have to see to it the client does not come to know the internal structure of the Microscope object. To solve this problem,we need to anticipate/forsee these changes in the future and make sure that the return type of the getters is of type Object.However, if you are pretty confident that the focusAxisPosition in the future is going to hold only numeric values, then abstract java.lang.Number would suffice. So your code would like this :
By changing the return type from primitive data types to Object type we get the following advantages :
The client would never come to know about the internal representation of Microscope object - i.e. how focusAxisPosition attribute is stored.
In future,if you need more precision, you would only have to change private float focusAxisPosition; to private double focusAxisPosition;.Note that the method does not undergo a change.Probably, you would only need to update the client about using Number.doubleValue() instead of Number.floatValue().You may rely on JavaDoc for this.This ensures greater flexibility for your changing design needs.