Forums Register Login

Designing an address book in Java

+Pie Number of slices to send: Send
I am designing an address book. I have come up with the following design:

Address Book:
Attributes : Entry
Methods: add(), delete(), search()

Entry:
Attributes : Name, Address, Phone Number
Methods: addName(),editName(),deleteName(),addPhone(),editPhone(),deletePhone(),addAddress(),editAddress(),deleteAddress()

Name:
Attributes: firstName, lastName

PhoneNumber:
Attributes:areaCode, phoneNumber

Address:
Attributes:streetNumber,streetName,city,zip.

Please review and comment on the design.



+Pie Number of slices to send: Send
In your Entry class, I would probably just use setters and getters. Deleting an attribute is then equivalent to setAttribute(null). For the rest it looks decent.
+Pie Number of slices to send: Send
Thanks. So my methods would be getName(), setName(Name n), getPhone(), setPhone(PhoneNumber num), getAddress(), setAddress(Address addr)

So, instead of a valid name, the user has to pass null to the setName() method to delete the name? Is passing null to a method acceptable?
+Pie Number of slices to send: Send
Absolutely. Even though null means as much as "no value", you can still assign a meaning to it. In your method's contract, explain to the user what it means to pass null into a method. In this case, it means to delete the name/phone number/address.
+Pie Number of slices to send: Send
OK, thank you
+Pie Number of slices to send: Send
I think you are designing the address book the wrong way. You are going on about the details of what to enter, but you have not apparently designed the general structure of the address book.
Then you can add things like phone number, street and postal code/zip to the entry; You can even alter the entry later: for example you can have friends in different countries so you can add country code to the phone number.
Design the general strcuture of the address book first, then add those details later.

I do not like nulls, but there are some places where they are unavoidable, so you have to allow for them in your design, as Stephan said. As an alternative to making the address null, you can use a data structure which has a method like remove(), and use that in your delete() method.
+Pie Number of slices to send: Send
Thanks Campbell. Do you mean I should think about how I will store my entries? Think about what data structure I'll be using? Or, are there other things that I'm missing in an address book?
+Pie Number of slices to send: Send
 

Campbell Ritchie wrote:I do not like nulls...


Me neither, but I suspect it's because I'm an ornery old database guy, and they violate third normal form (and very often a few lower ones too); but I understand that they are sometimes a necessary evil (or kludge ) in designing program structures.

@Saikrishnan: One of the things to think about is: What causes an address entry to be created?

That will hopefully point you as to what its key should be; and keys should always be required. Off the top of my head, I'd say that it should probably be the name, so you should never be able to delete that, no matter how you implement "deletion", without deleting the entire entry from the address book. Keys should also generally not be changed, so if you find yourself needing to do that, you should think about a delete→add operation.

HIH (and there's a lot to know about this stuff )

Winston
+Pie Number of slices to send: Send
- An AdressBook will have a collection of different entries so you might want to update the design of AddressBook class.
- Try to follow JavaBean naming convention.
- If you see that the attribute can be updated/modified then provide a setter method for the attribute otherwise if you find that the attribute is initialized with a value once in the constructor and never modified there after then you need not provide the setter method for the attribute.

+Pie Number of slices to send: Send
 

Saikrishnan Srivatsan wrote:Thanks Campbell. Do you mean I should think about how I will store my entries? Think about what data structure I'll be using? Or, are there other things that I'm missing in an address book?

You're welcome

Yes, how are you going to store the entries and what sort of data structure?
Remember, you can amend the Address class very easily if necessary.
+Pie Number of slices to send: Send
I thought I'd store my entries like this:

HashMap<Name,Entry> entries = new HashMap<Name, Entry>();
+Pie Number of slices to send: Send
 

Saikrishnan Srivatsan wrote:I thought I'd store my entries like this:
HashMap<Name,Entry> entries = new HashMap<Name, Entry>();


Seems reasonable, but then the question begs: Should Name be part of an Entry? Maybe, but it's worth thinking about.

Winston
+Pie Number of slices to send: Send
 

Saikrishnan Srivatsan wrote:I thought I'd store my entries like this:

That's good, but it should be:-

Map<Name,Entry> entries = new HashMap<Name, Entry>();

Make sure the Name class is immutable. Entry is a bad name because a Map already has a nested interface called Entry.
+Pie Number of slices to send: Send
 

Campbell Ritchie wrote:it should be:-
Map<Name,Entry> entries = new HashMap<Name, Entry>();


I understand the concept of dynamic look-up that Java does but haven't come across a real life example to understand why I really need to declare things the one above as the super type. Is this something that someone can explain or maybe point me to other threads where this has been discussed? I can't understand here whyis bad
+Pie Number of slices to send: Send
 

Saikrishnan Srivatsan wrote:

Campbell Ritchie wrote:it should be:-
Map<Name,Entry> entries = new HashMap<Name, Entry>();


I understand the concept of dynamic look-up that Java does but haven't come across a real life example to understand why I really need to declare things the one above as the super type. Is this something that someone can explain or maybe point me to other threads where this has been discussed? I can't understand here whyis bad



its a good idea to code to interfaces instead of implementations, this allows more flexibility in your code since you can swap out the HashMap for a different subclass without major refactoring.
+Pie Number of slices to send: Send
Thank you Michael. I still don't understand this Why will I not be able to change if I have the implementing type instead of the interface type?
+Pie Number of slices to send: Send
If you change the implementation rather than the interface your changes are very slight:-… can be changed to LinkedList or Vector by changing one word and everything else will work.
1
+Pie Number of slices to send: Send
 

Saikrishnan Srivatsan wrote:Why will I not be able to change if I have the implementing type instead of the interface type?


You will be able to change it - you can re-write an entire program (or indeed, application) if you want to - but the change is likely to be much more extensive (and therefore error-prone) because you will have to change every place that relies on that implementation.

If you use an interface - eg, List, as in the examples you've been shown - everywhere except the place that you actually initialize, then you can change the implementation for the entire program by simply choosing another class that implements List.

HIH

Winston
+Pie Number of slices to send: Send
I have come up with the following list of classes, attributes and methods after making minor modifications.

My idea is, when a user wants to add a new contact, the address book creates an empty contact object and returns it. The user has to use this object to set the Name and Phone number using setName() and the setPhoneNumber() methods in Contact rather than using the getters and setters in Name, directly. Is this acceptable?

AddressBook
Attributes - Map<Name, Contact>contacts, int size
Methods - Contact createContact(), void saveContact(Contact), void removeContact(Contact), int getSize(), void displayContacts(),
Contact searchByName(), Contact searchByPhoneNumber()

Contact
Attributes - Name name, String phoneNumber
Methods - Name getName(), String getPhoneNumber(), void setName(String firstName, String lastName), void setPhoneNumber(String phoneNumber)

Name
Attributes - String firstName, String lastName
Methods - String getFirstName(), String getLastName(), void setFirstName(String firstName), setLastName(String lastName)

+Pie Number of slices to send: Send
How does search by phone number work? That looks interesting.

I would prefer to have a name in every Entry; avoid nulls like the plague. So I would set up the name and as many other fields as possible in the constructor.
You will have to decide what to do with nulls because everynow and then you will find people who lack a certain detail (e.g. phone number) or where you don't know it, so you may find nulls are unavoidable.
+Pie Number of slices to send: Send
Even though I return an empty Contact object to the user at first, I plan to check for null once he updates the contact object and requests that it be added to the address book by calling saveContact(Contact).
+Pie Number of slices to send: Send
Campbell, I don't understand why you say it will propagate nulls. Is using the constructor to get the first and last names, then constructing a Name object better than doing it via a method in the Address book class?
+Pie Number of slices to send: Send
I didn't say it would propagate nulls; I said that nulls would be unavoidable and you would have to work out how to handle them.
+Pie Number of slices to send: Send
Thank you. If I check for nulls before adding to my hashmap, is my design right? Are there things in my design that are flawed or are there things that I've missed?
+Pie Number of slices to send: Send
Don't know; I haven't read the whole thread carefully.
Yes, you are right to check for nulls before letting anything into the Map. But the way I see it, that implies that non‑nullity (for some fields) is an invariant of the Entry class, so the Entry class or the Address class should monitor their own fields (or some of them) for nullity.
+Pie Number of slices to send: Send
Thank you. My Contact class has a Name field.

Name has firstName and lastName as attributes.

Should I expose the Name class to the user, let him create a name object, then pass it to the Contact constructor or have the Contact constructor take 2 strings for first name and last name and then make a name object from there?
+Pie Number of slices to send: Send
That's a good question. One response to it is "Well, why do you need a Name class anyway? Why not just let the Contact object contain the first and last names?" And then one response to that is "Because I might want to have more than one Contact for a Name."

I don't know whether either of those responses are valid in your case, but it does highlight the fact that your data design is not quite complete. Is the relationship between Contact and Name to be one-to-one, or one-to-many, or even many-to-many?
+Pie Number of slices to send: Send
Thank you Paul. I actually didn't even think about the relationship between Contact and Name when I wrote the Name class, but I think that I will permit more than one contact for a name. I have a few questions now:

1) If I want to store only one contact against a name, can I just have first and last name fields as strings in the Contact class and then have the user pass them to the constructor? I thought having Strings here was bad.

2)

Paul Clapham wrote:"Well, why do you need a Name class anyway? Why not just let the Contact object contain the first and last names?" And then one response to that is "Because I might want to have more than one Contact for a Name."

If I have a Name class, how can I allow multiple contacts to be stored against a name? I am not able to override my hashcode() and equals() appropriately to make this work.

+Pie Number of slices to send: Send
You can have a List<XXX> as the “V” of a Map.
+Pie Number of slices to send: Send
 

Campbell Ritchie wrote:You can have a List<XXX> as the “V” of a Map.

Thank you, Campbell. I still don't need a Name class to do this, correct?
+Pie Number of slices to send: Send
Not certain, but I think you probably will need a Name class. You can have a name field in the address book entry.
+Pie Number of slices to send: Send
I thought I could have first name and last name fields, and then pass as key to the Map.
+Pie Number of slices to send: Send
So what happens when you have saikrishnan srivatsan and saikrish nansrivatsan both in the same address book?
+Pie Number of slices to send: Send
Sorry, I meant Will this work without the need for a Name class?
+Pie Number of slices to send: Send
If you allow for all combinations of middle name, etc., it should work, yes.
+Pie Number of slices to send: Send
Thank you. Now, suppose I have the following entry in my address book:

Andrew Smith - 00000
Andrew Smith - 11111

The above entry would be stored with "Andrew Smith" as key and the value would be a "list" containing the 2 items above.

Suppose the user wants to change the phone number "00000" to "22222"; how do I manage that edit operation? Can I return a Contact object in the searchByName() method, then have him change that Contact object directly by having a public setPhoneNumber() method in the Contact class?
+Pie Number of slices to send: Send
I've coded the Name and Contact classes. I am not happy with the way I've coded the Contact constructor, but I am not able to think of any other way to do it Can someone kindly review the design?
+Pie Number of slices to send: Send
Why do you have public classes with package‑private constructors?
If you have a Name class, why are you not using it in Contact? In that case the validation should be done in Contact Name.
I like the way you are validating names, but surely you would throw an IllegalArgumentException?
Don't you have a PhoneNumber class?
+Pie Number of slices to send: Send
Sorry. made a mistake and had to change Contact to Name.
+Pie Number of slices to send: Send
Thank you for your response, Campbell.

Campbell Ritchie wrote:Why do you have public classes with package‑private constructors?

I'll make the constructors public as well.

Campbell Ritchie wrote:If you have a Name class, why are you not using it in Contact? In that case the validation should be done in Contact Name.

OK, here's where I was a bit confused. So, is it OK to expose the Name class to the user? If I had a PhoneNumber class, then I'd expose that too? Basically, the user would first use all my "attribute" classes to construct the "attribute" objects and then call the Contact constructor to pass Name, PhoneNumber etc.?

Campbell Ritchie wrote:I like the way you are validating names, but surely you would throw an IllegalArgumentException?

I thought I should be creating my own custom exceptions here. In what cases should I be creating custom exceptions then?

Campbell Ritchie wrote:Don't you have a PhoneNumber class?

I am planning to have one, but I wanted to confirm that I was on the right track before doing too much code.
What a stench! Central nervous system shutting down. Save yourself tiny ad!
a bit of art, as a gift, that will fit in a stocking
https://gardener-gift.com


reply
reply
This thread has been viewed 8083 times.
Similar Threads
address book
Cascading problem
XML Node Parsing Problem , when Node owns NodeList using Xercer , HELP !!!!
bringing up simple form in spring
Unmarshalling of nested child elements using jaxb
More...

All times above are in ranch (not your local) time.
The current ranch time is
Mar 29, 2024 01:30:36.