|
|
Lab
4
For this lab we will be stepping away from the Station class and
working instead on some location components. We won't be
rewriting the Location class from Lab 2, but will be taking that
information and building 2 new classes which can be used to locate the
closest station or stations within a specified distance. Think of
those applications on the web - perhaps you are on the Target.com
website or any other store web site and they ask you to enter your zip
code and after you do they give you a list of stores within x number of
miles to your zip code. The components we are working on for this
lab will assist in this type of application. They are not the
application itself, but rather the pieces that would be required for
that type of application.
This lab will be using the Location
class from Lab 2. You do not need to write this class and you
will not see this class when you open the project, but the executable
(.jar file) is there which will allow you to create objects and call
methods.
***Do not modify the driver class. This is simply there to
provide you with some output - it is not part of the lab. If
Webcat identifies any problems with the driver program - just ignore
them. I will adjust your score accordingly. You can
also
opt to remove the driver class and not submit it to Webcat.
You are only to make
modifications to the actual code of a method as indicated.
Never
change the declaration statement. Webcat and the various
testing
methods are expecting the declaration statements to be specified exactly
as they are given.
Step
1
- read through the lab instructions in the Word document.
While
the scenario presented is for fun, there is some key information that
should be gleaned from the instructions.
Here are some key points that I pulled out of the documentation:
- collection of Postal Zones - Postal Zones will be a new class, a collection is a list such as an array or an array List
- 2 new classes
- Postal Zone Class - models postal zones (zip codes)
- zip code - String data type
- centroid location - fancy name for a Location object (we created this as part of Lab 2)
- Location object contains latitude and longitude of a point near the center of the region for the zip code
- methods will be:
- constructor
- set/get methods for the instance variables
- ZoneCollection class - contains a collection of PostalZone objects
- instance variables
- array containing PostalZone objects
- position - integer data type
- will hold the number of elements currently in the array and the position where the next element should be added
- consider
- if the value this variable holds is 0 that means there are 0 postal
zones currently in the array and that if a new postal zone were to be
added it would be added into position 0
- remember,
the length of the array (25) says that's the maximum that can be added,
it doesn't say that is how many have been added
- methods
- addPostalZone - add a postal zone object to the array, returning true if successful, false if not
- getZoneCount - return the number of postal zone objects currently in the array
- postalZoneExists - return true if a zip code is found in one of the postal zone objects in the array, false if not
- getZoneLocation - return the Location object associated with the zip code of a postal zone object in the array
- countNearbyZones - return the number of postal zone objects in the array that fall within a specified distance
- findClosestZone - returns zip code of the postal zone object in the array that is closest to the target
- toString - returns formatted string with postal zones from the array
- constant variables
- NO_MATCHING_ZIP - will be returned when the getZoneLocation method does not find a zip in the collection
- COLLECTION_EMPTY - will be returned when the findClosestZone method encounters an empty array
Step
2
- now let's take a look at the program documentation. The
javadocs have already been created for you in this project.
Javadocs provide a description of each method including the
purpose, what will be returned, if anything, and what explicit
parameters are to be provided, if any. This is really helpful
information that you will definitely want to check out before you begin
working on your test cases - which is what you should do BEFORE you
begin working on the program itself.
To generate the
documentation in BlueJ, select TOOLS, PROJECT DOCUMENTATION.
When you view the
documentation, you will see a listing for both of the constructors and
all of the methods. If you click on a constructor or method
name
you will be taken to that particular constructor or method where you
will be able to see a description of the method. You will
also be
shown what will be returned, if anything, and what explicit parameters
are expected if any. A description of each is provided.
This is really useful information and can guide you as you
develop your test cases and eventually start working on coding the
object itself.
Step
3 While
it is tempting to work on this entire lab all at once, I would like to
recommend that you break it into pieces. There are 2 clear pieces
to this lab, the PostalZone class and the ZoneCollection class.
The ZoneCollection class is dependent upon he PostalZone class.
In other words, the ZoneCollection class will NOT work if the
PostalZone class is not working. So - work first on the
PostalZone class. Get it 100% operational and tested and then
move on to the ZoneCollection class.
Step
4a PostalZone Test
- develop the test cases for the constructor and set methods.
First
- test cases. There is one constructor. Remember, the format for testing a
constructor is:
- create a PostalZone object using the default constructor
- test and make sure the object has been created using the assertNotNull
- check each of the instance fields to make sure they contain the default value
- There are2 instance fields
- a string that stores the zip code
- a Location object that contains the longitude and latitude for the zip code
- So,
check and make sure the zip code instance field equals the value supplied to the constructor and using the
Location object methods, get the longitude and latitude and make sure
they equal the values supplied to the constructor.
Next
write the test cases for the set/get methods. There will be only
2. One to test the set/get for the zip code instance field and
one to test the set/get for the Location instance field. Remember
the format for testing set/get methods is:
- create the PostalZone object using the explicit constructor
- call the set method changing the value of an instance field
- call the get method to retrieve the value
- For
ZoneLocation a Location object will be returned. To make sure the
Location object contains the correct values for latitude and longitude
you will need to use the returned Location object to call the Location
object get methods to get the longitude/latitude
- use assertEquals to make sure the values are equal
Step 5a PostalZone
- write the PostalZone class
There is just 1 constructor, 2 set methods, and 2 get methods for this class.
Constructor
- Initialize the zip code instance variable to the explicit parameter passed to this constructor
- A
latitude and longitude are passed to the constructor, but the instance
variable is a Location object. Use the explicit parameters of
latitude and longitude to create a Location object and assign your
instance variable equal to this new Location object
- zipLocation = new Location(inLat, inLat) --- just an example, has to be modified to fit the situation
- You did this exact thing in Lab 2 with your Station class.
Write
the set/get methods for the instance fields.
setZoneLocation
- A
latitude and longitude are passed as explicit parameters to this
method. As in the constructor you will need to create a Location
object and then assign the zipLocation instance variable equal to this
object.
getZoneLocation
- It
is tempting to just return the zipLocation instance variable, but in
doing do you are not just returning the data associated with the
instance variable, but the memory location for the instance variable
itself. (Remember the rectangle homework from week 3) You
don't want to do that or you will be giving someone else control to
your data. Instead return a copy of the zipLocation. Create
a brand new Location object using the data from the zipLocation
instance variable.
- get the latitude from zipLocation
- get the longitude from zipLocation
- using this information create a brand new Location object
- return this brand new Location object
Step 6a -
Compile both your PostalZone and PostalZoneTest classes. When
they
compile
cleanly - no syntax errors, run your tests. Did all of your test
case pass? If so you are ready to
proceed on to the next portion of the code. If not - then go back
and
review your logic and make corrections. Do not proceed until
these are
working correctly! Remember - the ZoneCollection class is
dependent upon the PostalZone class and will not work if this class is
not working.
Step b ZoneCollection
I
actually recommend that you break this class down into 2 pieces.
Work first on the constructor, add, exists, and count methods and
once these are complete then work on the methods to find the closest
zones or the zones within a specified distance and the tostring.
The reality is that unless the add and exists methods are
working, these labs will not work so it's important to ensure these are
working correctly before working on the last methods. Step
4b ZoneCollection Test
- develop the test cases for the constructor, add, exists, and count methods
setUp()
- Notice
that a ZoneCollection object is created in the setUp() method and that
the addPostalZone method is called several times to add items to the
collection.
- This object has been created so that you can use
this with your test cases. You DO NOT have to use this zone
collection object, but you are certainly welcome to do so.
Test the constructor
Remember the format for testing a constructor is:
- create the ZoneCollection object using the constructor to be tested
- test and make sure the object has been created using the assertNotNull
- check each of the instance fields to make sure they contain the default value
- In
this case the instance field is an array and a count. The array will be
defined, but empty. We can't get to the array because it is
declared as private and protected via encapsulation - hiding of
unimportant details. So, the only thing we can check is the next
position variable - it should be zero, right? Nothing has been
added to the array so the next position should be the first position
which is zero.
Test the addPostalZone method
The
purpose of this method is to add a PostalZone object to the array.
In order to do so, though, there must be room in the array.
The array has a maximum size of 25, so before adding the count
must be checked to make sure there is room and if there is add the
object and return true. If there is not return false. Your
testing will need to take both circumstances into account. This
will involve adding 26 postal zone objects so that you can make sure
that you receive false when trying to add that 26th object.
- Create a new ZoneCollection object.
- call the add postal zone method
- check
and make sure that true is returned - the object was successfully added
- check the count and make sure it is equal to 1, 1 element now exists in the array
- Create a loop to keep adding
- for (int i=2; i <= 25; i++)
- Starting i with 2 because you've already added 1 postal zone object above.
- use i for the zip code, the latitude and the longitude
- it doesn't matter if these are valid values, just that we are adding something
- add the postal zone object
- check and make sure true is returned
- check and make the count value is equal to i (position added in array)
- end loop
- Now
- add just 1 more postal zone object. Prior to this add you should have added 25
postal zones. Adding 1 more puts you over 25 to number 26.
This should not be allowed and should return a value of false.
- add the zone object
- check and make sure false is returned
- make sure the count is still equal to 25
Test the PostalZoneExists Method Test
the postalZoneExists() method. This method returns true if a zip
code is found and false if a zip code is not found. The test for
this is very straight forward.
- Create a ZoneCollection object
- Add a postal zone object to the ZoneCollection object
- Call the postalZoneExists() method passing the zipcode that you used
- Make sure true is returned
- Call the postalZoneExists() method passing a zipcode you did not use
- Make sure false is returned
Test the getZoneLocation() method This method returns a postal zone object Location if found and a final constant NO_MATCHING_ZIP if not found.
- Create a ZoneCollection object.
- Call the getZoneLocation method for a zip code and ensure that NO_MATCHING_ZIP is returned.
- at
this point no postal zone have been added, no matter what zip code you
search for the NO_MATCHING_ZIP should be returned because the
ZoneCollection is empty
- Add a postal zone object to the ZoneCollection object
- Call the getZoneLocation() method passing the zipcode that you used
- Check
the returned location object latitude and longitude to make sure the
values match what you used when adding the postal zone object above
- The
above was done for you - but now you are to write your own test cases.
Use what was provided above as an example as you write your own
test cases.
Step 5b ZoneCollection
- write the initial methods for the ZoneCollection class
Constructor Remember the purpose of a constructor is to initialize the instance variables.
- the
array - the initial definition of the array has been completed int he
class, but notice there is not an equal sign. That means that the
variable zones has been identified that it will be an array of
PostalZone objects, but that it is not yet ready to be used.
- You need to complete the position to the right with the equal sign
- zones = then finish the definition of the array
- Remember DO NOT start with PostalZone [] zones =
- If you do this you will be creating a brand new location variable, not completing the definition of your instance variable
- zoneCount - set this to 0
- nothing has been added to the array at this point, the count of items in the array is equal to 0
getZoneCount The
purpose of this method is to return the number of PostalZone elements
that have been added to the array. This is not the length of the
array, but the number of elements that have been added to the array.
This value is being kept in your instance variable.
- return your zoneCount instance variable
addPostalZone The
purpose of this method is to add a new PostalZone object to the array.
Passed to this method are 3 explicit parameters, zip code,
latitude, and longitude.
- Check the zone count, if it's >24 then return false, the limit has been exceeded and the postal zone cannot be added
- Create a postal zone object using the explicit parameters passed to the method
- Add
the postal zone object to the postal zone array instance field and put
it into the position indicated by the next position counter
- increment the counter so that it contains the next position
- return true
postalZoneExists The
purpose of this method is to check for a zip code within the zone
collection array and return true if the zip code is found, false if it
is not.
- This involves a loop. You will need to loop
through the zone collection array checking each and every postal zone
object to see if it's zip code matches the zip code provided as an
explicit parameter. If you find a match, return true. If
you make it all the way through the loop and don't find a match return
false
- loop from 0 to less than the zone count
- why
zone count? why not the array length? zone count tells you
how many postal zone objects exist. There's no need to search the
entire array when many of these elements may be empty. It's much
more efficient to only search those elements that actually contain
postal zone objects.
- for each element position in the array
(position i) get the zip code by calling the getZoneZipCode() method of
the PostalZone object and then compare this value using the .equals()
string method to see if it equals the zip code explicit parameter
- if it is equal return true
- if you make it outside the loop that means no match was found, return false
getZoneLocation The
purpose of this method is to return a Location object for the specified
zipcode - the zip code passed in as an explicit parameter
- This method is really the same as postalZoneExists above.
- You will need to loop through the zone collection array searching for the zip code - just like you did above
- BUT
- instead of returning true when you find a match for the zip code, you
need to create a brand new Location object and return that object.
You don't want to just return the Location object that would give
someone outside your program control of your data (remember the
Rectangle class from Week 3).
- To create a copy
- call the PostalZone object method to get the Location object.
- call the getLatitude and getLongitude methods to retrieve these values
- create a brand new Location object using these values
- return the new location object
- if the zip code is not found - return the final constant NO_MATCHING_ZIP
Step 6b -
Compile both your ZoneCollection and ZoneCollection Test classes.
When they
compile
cleanly - no syntax errors, run your tests. Did all of your test
case pass for the code you have written? If so you are ready to
proceed on to the next portion of the code. If not - then go back
and
review your logic and make corrections.
Step
4c ZoneCollection Test
- develop the test cases for the remainder of the ZoneCollection class
Test the countNearbyZones method The
purpose of this method is to return a count of the number of postal
zones within the zone collection that fall within a specified distance
of a specified location. This distance is in miles and is passed
to the method as an explicit parameter. This would be very
similar to the Target.com example I provided above. To test this method:
- Create a ZoneCollection object.
- Create a Location object to be the target location.
- At this point your collection is empty.
- Call the countNearbyZones method passing the target and any distance.
- Check and make sure the count returned is 0. The collection is empty so no postal zones should fall within the range.
- Add some postal zone objects to the collection.
- Call the countNearbyZones method passing the target and a distance.
- Check and make sure the correct count is returned.
- ***You're
going to have to do some manual figuring so that you add zones that
fall within the distance and some that fall outside of the distance.
- ****Some
tests are provided for you. You are to write additional tests.
Do not omit the writing of additional tests. Points will be
manually deducted by me if you do not write the additional tests.
Test the findClosestZone method The
purpose of this method is to return zip code of the number of postal
zones within the zone collection that is closest to the specified location. The target location is passed to
the method as an explicit parameter. To test this method:
- Create a ZoneCollection object.
- Create a Location object to be the target location.
- At this point your collection is empty. Make sure the returned value is equal to the final constant COLLECTION_EMPTY.
- Call the findClosestZone method passing the target.
- Check
and make sure the final constant COLLECTION_EMPTY is returned.
The collection is empty so no postal zones should be found.
- Add some postal zone objects to the collection.
- Call the findClosestZone method passing the target.
- Check and make sure the returned zip code is what you were expecting.
- ***You're going to have to do some manual figuring to determine which zone is the closest.
- ****Some tests are provided for you. You
are to write additional tests. Do not omit the writing of additional
tests. Points will be manually deducted by me if you do not write the
additional tests.
Test the toString method The
purpose of this method is to create an output string of the postal zone
objects in the collection. To test this method:
- Create a ZoneCollection object.
- Call the toString method to ensure it returns the correct string when the collection is empty.
- Add postal zone objects to the collections
- Call the toString method to ensure it returns the correct string when there are zones in the collection.
Step 5c ZoneCollection
- write the remaining methods for the ZoneCollection class
countNearbyZones method The
purpose of this method is to return a count of the number of postal
zones within the zone collection that fall within a specified distance
of a specified location. This distance is in miles and is passed to
the method as an explicit parameter. This would be very similar to the
Target.com example I provided above.
Ok
- so first you will need a local variable to keep count of the postal
zones that are within the specified distance of the target location.
This variable should initially be set equal to 0.
Here is the basic algorithm for this method:
- initialize a local variable for count to 0
- loop through all of the postal zone objects in the zone collection array
- get the location for the postal zone object at zone collection position i in the array
- call
the calcDistance location method using the postal zone location object
and passing the target location object as the explicit parameter
- compare the returned distance to the distance explicit parameter
- if the distance is less than or equal to the distance explicit parameter add 1 to the count
- return the count local variable
findClosestZone method The
purpose of this method is to return zip code of the number of postal
zones within the zone collection that is closest to the specified location. The target location is passed to
the method as an explicit parameter.
You're going to need 2 local variables for this method.
- String variable to keep track of the closest zip code
- double variable to keep track of the distance from the zip code to the target
Here is the basic algorithm for this method:
- Check the zone count instance variable
- if this is equal to 0 - the array is empty, return COLLECTION_EMPTY
- set
string variable equal to the zip code for the postal zone object at
zone collection position 1 (the first postal zone in the array)
- remember
when you say zones[1] you are really saying the postal zone object at
position 1. You can then call the postal zone method to retrieve
the zip code.
- retrieve the Location object for the first
postal zone object in the array and call the calcDistance method using
this Location object and passing in the target location as the explicit
parameter. Put the distance that is returned into your local
variable.
- ***These variables are now set equal to the first
postal zone. This is our starting point. If we find a
postal zone that is closer than this first one we'll replace these
values.
- loop through the zone collection array from 1 (not 0,
but 1 so we're starting with the 2nd postal zone object) through the
zone count - no need to go all the way to the end of the array, just
through the elements we've added
- retrieve the location for the postal zone object at array position i
- call the calc distance to determine the distance to the target location
- compare the distance returned against the distance you have stored in your local variable
- if the distance is less than that in the local variable
- replace the distance with the new distance
- replace the zip code with the new zip code
- when the loop is done
- return the zip code in your local variable
toString method The purpose of this method is to create an output string of the postal zone objects in the collection.
This method has been written for you - but it's a good idea to review the code to ensure you know what it is doing.
Step 6c -
Compile both your ZoneCollection and ZoneCollection Test classes.
When they
compile
cleanly - no syntax errors, run your tests. Did all of your test case
pass for the code you have written? If so you are ready to
proceed on to the next portion of the code. If not - then go back
and
review your logic and make corrections.
Step 7 - update the Readme.txt
file. Specific information is required to be entered into this
file. Make sure you view the instructions for this file so that
you do not lose points for an incorrect format.
Step 8 - use
the check style feature in BlueJ. This can be found under Tools,
Checkstyle. This tool will evaluate your program for style.
Each of the classes will be listed. Clicking on a class
name will reveal any style problems that have been found. These
would include such things as lines that are too long, incorrect
indentation, missing periods, etc. Correct all of these identified
problems. Recompile, retest. ****It is really important
that you do this. For each check style error found, Webcat will
deduct 1 pt. These can really add up and you don't want to lose
points for things that can easily be corrected.
Step 9 - submit to WebCat.
This is not a one time submission. Webcat is a tool that
can be used to ensure you receive the maximum number of points possible. Submit, review the output. Make
corrections and submit again. Continue this process until you
have perfected your lab.
|