Tina Comston
Comp-111 Lab 4
Franklin University
Lab 4
Lab 4
  • Instructions - posted on Piazza
  • Data Files - Posted on Piazza
  • Readme.txt
  • WebCat
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)
      • instance variables
        • 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
          • size of array is 25
        • 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.
  1. String variable to keep track of the closest zip code
  2. 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.