wood burning stoves 2.0*
The moose likes OO, Patterns, UML and Refactoring and the fly likes How do I slim down a class full of get...() and set...() Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Spring in Action this week in the Spring forum!
JavaRanch » Java Forums » Engineering » OO, Patterns, UML and Refactoring
Bookmark "How do I slim down a class full of get...() and set...()" Watch "How do I slim down a class full of get...() and set...()" New topic
Author

How do I slim down a class full of get...() and set...()

James Beeson
Greenhorn

Joined: Apr 18, 2000
Posts: 18
In several Java books I have looked at, it is commonly said to use public get...() and set...() methods to provide access to private class attributes. While this is good for when you are starting out, one quickly learns that a better way to program is to write methods that offer services... that do the work you want them to do instead of GETing and SETing attributes all over the place. That makes very good sense as it would not clutter class.
But what if you have a class that all it is is a place to store data with no special processing code. Take the example below
public class Address {
private String address1;
private String address2;
private String city;
private String state;
private String zipcode;
// constructor
public Address(String address1, String address2, String city,
String State, String zipcode) {
this.address1 = address1;
this.address2 = address2;
this.city = city;
this.state= state;
this.zipcode= zipcode;
}
// methods to set the values of the attributes
public void setAddress1(String address1) {this.address1 = address1;}
public void setAddress2(String address2) {this.address2 = address2;}
public void setCity(String city) {this.city = city;}
public void setState(String state) {this.state= state;}
public void setZipcode(String zipcode) {this.zipcode= zipcode;}
// methods to retrieve the values
public String getAddress1() {return this.address1;}
public String getAddress1() {return this.address2 ;}
public String getAddress1() {return this.city;}
public String getAddress1() {return this.state;}
public String getAddress1() {return this.zipcode;}

}
My question is: is there a more efficient way to do this? That is, is there a better way to store attributes and accessor methods without having such bloated classes?
Thanks

Frank Carver
Sheriff

Joined: Jan 07, 1999
Posts: 6920
I think you are on the right track when you say a better way to program is to write methods that offer services. A class that is only used to store data is one of the classic Code Smells indicating that some refactoring is needed.
Now is the time to think hard about the real responsibilities of your address object. If lots of other objects need read access to its members, but writing to it is relatively infrequent, consider making it an immutable "value object" (consider a String - if you need to change it, create a new one) by making all the members public final and setting them in the constructor.
A better approach, though, is to encapsulate all the knowledge of address formats in this class, and only provide methods to alter or extract the address as a whole item. Do any of your other objects really need to know the difference between "address1" and "address2"? Does "alter just the zip code" really make sense as a UI operation?
As an aside, please beware of encoding US-specific address formats into your object model. One very strong argument in favour of preventing access to individual address elements is to make a single point of access for address format changes. I've ranted about this in other threads, but bear in mind that addresses in other countries may require more than two lines of text, don't necessarily have a "city", certainly won't have "state" or "zipcode", and may need other elements like county, province or departement.
Can you give use some more information about what other objects actually do with your address object? Are there any popular operations which could be moved into the address class?
[This message has been edited by Frank Carver (edited April 26, 2000).]


Read about me at frankcarver.me ~ Raspberry Alpha Omega ~ Frank's Punchbarrel Blog
paul wheaton
Trailboss

Joined: Dec 14, 1998
Posts: 20636
    ∞

I don't think it is too bulky.
The thing to remember is that at some later time you might decide to change how you store stuff and then some of your getter and setter methods may become slightly more sophisticated.
As Frank pointed out, you might work in other address formats or other info - different methods might change the same fields.


permaculture Wood Burning Stoves 2.0 - 4-DVD set
James Beeson
Greenhorn

Joined: Apr 18, 2000
Posts: 18
Just to give you the context, I am working on a GUI application designed to manage data about testing animals for various diseases for the state of Texas. I have several classes such as inspector (people who inspect animals for diseases), markets (places where animals are sold), and premises (ranches where herds of animals reside). All three of these (inspectors, markets, and premises) have address information. Each item has a data entry screen where its address information, as well as other information, will be edited.
The Address class I listed (see three posts up) is designed to store the address information for my Inspector, Market, and Premise classes. Here is the order of events that users will go through to edit the address:
For the sake of this example, I will discuss the markets, but inspectors and premises work the same way.
1) user selects �edit markets� from main menu
2) the market entry GUI appears with blank fields for the address information. My Market class has two Address objects- one for mailing address and one for physical address. Both of these objects were constructed so that all of the values (address1, address2, city, state, zip) set to empty Strings.
3) the users edits the address fields
4) the users saves the record, and values from the fields are dumped into the Address objects within the Market object.
Alternately, the user could:
1) see #1 above
2) see #2 above
3) user performs a search and selects the market they want to edit. The address information in the database is used to populate the Address objects within the Market class
4) see #3 above
5) see #4 above
My question still remains. Given the fact that this Address class could be used by several other classes, how do I set up this (and/or the other classes) so that they are not just a bunch of get...() / set...() loaded classes?

Also, I spend most of this morning looking at the web site from the �Code Smells� link above. Based on its description, I can see that this (and other) classes need refactoring, but I am unsure as to what to do.
HELP!!
eric moon
Ranch Hand

Joined: Nov 26, 2000
Posts: 133
Well, it may not be better, but it's different, at least! You could store your fields as key/value pairs in a HashMap. Then if you wanted to add a field, you could just store it under a new key. Then you just need one getter and one setter with a string to determine what you're getting or setting. Heck, make each value object in the map a vector, and you could put all your data in one object:
jebsZipcode = ((Vector)(map.get("zipcode")).get(recordNumber);
Advisable?? Heck if I know.
DB gurus?


<BLOCKQUOTE><font size="1" face="Verdana, Arial">quote:</font><HR>"Those who cast the votes decide nothing. Those who count the<BR>votes decide<BR>everything." <BR> -Joseph Stalin<HR></BLOCKQUOTE>
Michal Harezlak
Ranch Hand

Joined: Jul 06, 2000
Posts: 185
James:
IMHO there is nothing wrong with your design, (aside from internationalization issues.) The Address would be what you call pure data values or like Frank said value objects. They usually are created to satisfied needs for a non-primitive attribute type. The behavioral side for such classes is virtually non existing and attempts to introduce it could cause lost of cohesion.
[This message has been edited by Michal Harezlak (edited December 12, 2000).]
martin fowler
Author
Ranch Hand

Joined: Dec 11, 2000
Posts: 53
Certainly a class with only get and set methods is a smell. As others point out there may be other behavior that needs to go in there. However that behavior may not be apparant as yet. If you are just displaying information on a gui and using the address to put it away - then there's not much there other than the data. Yes it's a smell, but I wouldn't worry about it. Just be alert to behavior that should move into the class as you develop your application further.


author of:<br /><a href="http://www.amazon.com/exec/obidos/ASIN/0201485672/electricporkchop" target="_blank" rel="nofollow">Refactoring : Improving the Design of Existing Code</a><br /><a href="http://www.amazon.com/exec/obidos/ASIN/020165783X/electricporkchop" target="_blank" rel="nofollow">UML Distilled, Second Edition: A Brief Guide to the Standard Object Modeling Language</a><br /><a href="http://www.amazon.com/exec/obidos/ASIN/0201895420/electricporkchop" target="_blank" rel="nofollow">Analysis Patterns : Reusable Object Models</a><br /><a href="http://www.amazon.com/exec/obidos/ASIN/0201710919/electricporkchop" target="_blank" rel="nofollow">Planning Extreme Programming</a>
martin fowler
Author
Ranch Hand

Joined: Dec 11, 2000
Posts: 53
Originally posted by eric moon:
Well, it may not be better, but it's different, at least! You could store your fields as key/value pairs in a HashMap. Then if you wanted to add a field, you could just store it under a new key. Then you just need one getter and one setter with a string to determine what you're getting or setting. Heck, make each value object in the map a vector, and you could put all your data in one object:
jebsZipcode = ((Vector)(map.get("zipcode")).get(recordNumber);
Advisable?? Heck if I know.
DB gurus?

I wouldn't reccomend this approach. The problem is that by using a map your interface is no longer explicit. Clients have to look up the keys for the hash map (which don't appear in the code) to figure out what whether to use "zip" or "zipcode" for your zip code. Occasionally a map is a good idea when instances have very variable properties (Kent Beck refers to this as "variable state" in his Smalltalk pattern book). But I wouldn't use it here.
martin fowler
Author
Ranch Hand

Joined: Dec 11, 2000
Posts: 53
Originally posted by Frank Carver:

As an aside, please beware of encoding US-specific address formats into your object model. One very strong argument in favour of preventing access to individual address elements is to make a single point of access for address format changes. I've ranted about this in other threads, but bear in mind that addresses in other countries may require more than two lines of text, don't necessarily have a "city", certainly won't have "state" or "zipcode", and may need other elements like county, province or departement.

That's a danger, but putting in international address capability requires a lot of effort and YAGNI applies.
Michal Harezlak
Ranch Hand

Joined: Jul 06, 2000
Posts: 185
Originally posted by martin fowler:
[...]As others point out there may be other behavior that needs to go in there. [...]

Martin:
That is interesting. Could you please elaborate on it. What behavior do you have in mind for the Address class? I can see that a class like OfficeAddress (perhaps derived from the address class) could have some operations, but I fail to see any potential operations for Address class itself. Thanks in advance.

martin fowler
Author
Ranch Hand

Joined: Dec 11, 2000
Posts: 53
The problem with just suggesting behavior is that behavior if often application specific, so my suggestions may not make sense for James.
One thing might be validation behavior. Does this zip actually fit in this state? Or you might infer city and state from the zip. You might create an address with one big string and the address parses it up into its peices (like Outlook does when you type in a big address). You might want to know the distance between two addresses, or use Mapquest to show the route between two addresses. You might want to know which address is the most northerly, or tell me the average temperature for a certain month of an address, or number of bars within a 3 mile radius (that one sounds useful).
There's a lot of behavior here, some of which would use collaborators. But they're all possibilities, depending on the use cases that you actually have to implement.
Martin
Michal Harezlak
Ranch Hand

Joined: Jul 06, 2000
Posts: 185
Thanks a lot Martin. That made me realize couple of my own design mistakes. I need to be paying more attention to YAGNI concept.
Frank Carver
Sheriff

Joined: Jan 07, 1999
Posts: 6920
Hmm. An old thread arises from the virtual grave.
One of the problems with YAGNI is that to apply it you really have to know what you need right now. The ability to accept international addresses is an interesting case. At least once a week I fall foul of US-originated e-commerce implementations which won't accept even my relatively friendly UK address. Those companies don't get my business. Not for vague, philosophical reasons, but because I simply can't tell them that I want to be a customer.
For me the "simplest thing" is to hold an address as just a text string suitable for postal labels. That's its basic function, after all. All other derived information should be optional and subject to YAGNI. Do you really need to know at the moment what your customer's zip code is? In what important way is a second line of a street address different from a first?
It's seems endemic in (mostly US-authored?) programming textbooks to treat this dissection of address information as a fundamental programming process, and thus people naturally do it when asked to represent an address in a software system. From time to time I boil over (as I did early in this thread) and ask people to reconsider just why they are storing all these component parts of an address in such a US-specific way.
There are, of course, arguments in favour of dividing up an address. The most valid are those which actually affect business, such as state-specific taxes and export licence requirements. Even for these, though, I would recommend that such questions be asked separately "Are you a resident of Texas?". One argument I consider less useful is the argument based on the need for validation of the address. Would you rather lose the custom of a few billion people across the world, or a very small number (I hope) of US-residents who don't even know their own address
martin fowler
Author
Ranch Hand

Joined: Dec 11, 2000
Posts: 53
Originally posted by Frank Carver:
For me the "simplest thing" is to hold an address as just a text string suitable for postal labels. That's its basic function, after all. All other derived information should be optional and subject to YAGNI. Do you really need to know at the moment what your customer's zip code is? In what important way is a second line of a street address different from a first?

I agree, a lot of the time just one big text block is all you ever need. The way you can tell is to look at the behavior. If you do nothing with an address but get and set - then a text block is better. If you do have some behavior - such as state for tax reasons, then you have a force to start breaking it apart.
Michal Harezlak
Ranch Hand

Joined: Jul 06, 2000
Posts: 185
... just wondering. Would using XML with the big text block solution add some value [standardized access to fields of the address] to it. Would that be a sound design decision when our Address concept �has� a behavior?
martin fowler
Author
Ranch Hand

Joined: Dec 11, 2000
Posts: 53
Originally posted by Michal Harezlak:
... just wondering. Would using XML with the big text block solution add some value [standardized access to fields of the address] to it. Would that be a sound design decision when our Address concept ?has? a behavior?

I would never use XML when I could use an object instead.
So don't use XML text blocks to pass information between objects in the same process, unless you're parsing, generating, or handing off that XML
However XML is a good way to pass information between objects in seperate processes, although a serialized Java object is better if you can do that.
To access information from XML requires a lot of messing around with DOMs, even if you use JDOM. It's much better to call methods on classes if that option's available to you.
Martin

------------------
author of:
Refactoring : Improving the Design of Existing Code
UML Distilled, Second Edition: A Brief Guide to the Standard Object Modeling Language
Analysis Patterns : Reusable Object Models
Planning Extreme Programming
Michal Harezlak
Ranch Hand

Joined: Jul 06, 2000
Posts: 185
Thanks Martin, I see what you are saying. After thinking about it for a while and I am starting to suspect that this approach would not be appropriate for another reason. Isn't it introducing specific technology solution too early in the process?
Mirko Froehlich
Ranch Hand

Joined: Aug 21, 2000
Posts: 114
Particularly in E-Commerce applications, you often need to break addresses apart into multiple fields as opposed to storing them as a single string, for example because of credit card processing. I have worked with an E-Commerce framework that used Cybercash for credit card processing (it actually had a pluggable architecture so that other processing systems could be used instead). Cybercash (and I assume most other processing systems too) requires individual fields, and it would be practically impossible to correctly parse an address string in all cases. Also, since addresses are entered on a web page, you have the individual fields anyway. Sure, you could use a text box for the complete address, but then you would not be able to tell if certain important pieces (like the city) might be missing.
-Mirko

Originally posted by Frank Carver:
Hmm. An old thread arises from the virtual grave.
One of the problems with YAGNI is that to apply it you really have to know what you need right now. The ability to accept international addresses is an interesting case. At least once a week I fall foul of US-originated e-commerce implementations which won't accept even my relatively friendly UK address. Those companies don't get my business. Not for vague, philosophical reasons, but because I simply can't tell them that I want to be a customer.
For me the "simplest thing" is to hold an address as just a text string suitable for postal labels. That's its basic function, after all. All other derived information should be optional and subject to YAGNI. Do you really need to know at the moment what your customer's zip code is? In what important way is a second line of a street address different from a first?
It's seems endemic in (mostly US-authored?) programming textbooks to treat this dissection of address information as a fundamental programming process, and thus people naturally do it when asked to represent an address in a software system. From time to time I boil over (as I did early in this thread) and ask people to reconsider just why they are storing all these component parts of an address in such a US-specific way.
There are, of course, arguments in favour of dividing up an address. The most valid are those which actually affect business, such as state-specific taxes and export licence requirements. Even for these, though, I would recommend that such questions be asked separately "Are you a resident of Texas?". One argument I consider less useful is the argument based on the need for validation of the address. Would you rather lose the custom of a few billion people across the world, or a very small number (I hope) of US-residents who don't even know their own address

 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: How do I slim down a class full of get...() and set...()