PA2: Big Box Bargains
Categories:
13 minute read
Programming Assignment 2

🛑 To Know Before You Start
Though the classes you must write are not terribly large, and the input/output is similar to what was required to complete the previous assignment, this assignment will be fairly time consuming. This is both because it deals with the most difficult concepts that we have considered this semester, and because you will need to spend a lot of time writing tests.Learning Objectives
This programming assignment is designed to help you learn several things. First, it will help you learn about interfaces and abstract classes, and improve your understanding of specialization. Second it will help you learn about polymorphism and dynamic binding. Third, it will help you learn about static binding. Finally, it will help reinforce your understanding of I/O, packages, and unit testing.
Overview
Big Box Bargains (BBB), a new “big box” store that hopes to compete with stores like Costco and Sam’s Club, has contracted with you to write some of the software they need for their checkout system.
The Components to be Written
You must write the Account and VIPAccount classes that encapsulate
membership information that is specific to BBB, as well as some
general purpose components for performing input/output operations on
comma-separated-value (CSV) files. The relationship between these components
is illustrated in the following UML class diagram.

Note that methods in a class that are “concrete” implementations of abstract methods
(that are listed either in an interface or an abstract class) are not explicitly listed in
the class (e.g., the toCSV() method in the Account class). Method in a derived class
that override a method in a base class are explicitly listed in the derived
class (e.g., the toCSV() method in the VIPAccount class).
🛑 Italics
On some displays, it may be difficult to distinguish the italic font from the upright font in this class diagram. So that there is no confusion, the following are italicized: thefromCSV() and toCSV() methods in the CSVRepresentable interface,
the name of the FileProcessor class, and the decrypt() and encrypt()
methods in the FileProcessor class.The CSVRepresentable Interface
The CSVRepresentable interface describes the capabilities of objects
that can be represented in simplified CSV format (i.e., all of the fields
are delimited by commas, the fields are assumed to not contain commas,
and there are no column headers). The toCSV() method says that
such an object must be able to create a String representation of
its attributes in simplified CSV format. The fromCSV() method, on the other hand, says that such an
object must be able to initialize its attributes from a String
representation in simplified CSV format.
Obviously, the fromCSV() method must tokenize the String that it
is passed (that has a comma as the delimiter between tokens). In
principle, this can be done in many ways, but you must choose between
two. Specifically, you must use either a Scanner or a StringTokenizer
(both of which are in the java.util package) for this purpose. The
fromCSV() method returns the object used for tokenizing the String
so that it may be used to tokenize any remaining tokens in the
String. In other words, the String representation may contain more
tokens than the fromCSV() method uses, so it must return the object used
for tokenzing in case these tokens need to be used elsewhere.
The FileIdentifier Class
The FileIdentifier class encapsulates the “classic” two-part approach
to identifying files. In this “classic” approach, a file identifier
consists of a name (the portion to the left of the dot) and an
extension or type (the portion to the right of the dot). So, for
example, one might identify the file named Student.java using a
FileIdentifier that has a name attribute of "Student" and an
extension attribute of "java".
This class implements/realizes the CSVRepresentable interface because
it is common to include FileIdentifier objects in CSV files.
The toString() method must return the name and extension formatted using the
format String "%s.%s".
The FileProcessor Class
The FileProcessor class is an abstract encapsulation of an object
that can read from and write to the file system in a line-oriented
way. The first line of any file it reads or writes must contain the
number of lines in the file.
This class supports encryption and decryption, but those capabilities must be provided by derived classes. In addition to the specifications contained in the UML class diagram, this class must conform to the following specifications.
The
readLines()method must first read the number of lines in the file. It must then read the subsequent lines, decrypt them, and return aString[]array that contains the decrypted lines.The
writeLines()method must first write the length of the parameter namedlines(on a line of its own). It must then encrypt the elements and write them to the file (one element per line).
The CSVFileProcessor Class
The CSVFileProcessor class is a concrete specialization of the
FileProcessor class. In addition to the specifications contained in
the UML class diagram, this class must conform to the following
specifications.
The
decrypt()andencrypt()methods must return the parameters they are passed unchanged. In other words, CSV files must not be encrypted.The
write()method must create a CSV representation of the objects it is passed and write all of them to the appropriate file (that is passed to the constructor), one per line.The
read()method must read all of the records from the appropriate file (that is passed to the constructor) and initialize the attributes of the objects that it is passed. It must assume that it is passed an array of objects that has the same number of elements as there are records (one per line) in the file. (Note: This method does not return the elements it reads. Instead, it sets the attributes of eachCSVRepresentableobject it is passed, using thatCSVReprentableobject’sfromCSV()method.)The
write()andread()methods must not duplicate any code in theFileProcessorclass or in the class of theCSVRepresentableobjects that it is passed.
The Account Class
The Account class is an encapsulation of a membership account at BBB.
In addition to the specifications contained in the UML class diagram,
this class must conform to the following specifications.
The
purchasesattribute must be used to keep track of the total purchases made by the member (measured in dollars), and thecreditsUsedattribute must be used to keep track of the total credits used by the member (measured in dollars).The default constructor must initialize both attributes to 0.00.
The
availableCredit()method must return the available credit, which is based on a percentage (obtained fromgetRewardPercentage()) of thepurchasesattribute minus the credits used to date. So, for example, ifpurchasesis 2000.00,getRewardsPercentage()returns 0.01, andcreditsUsedis 5.00, then this method must return 15.00. Note that the value returned must never be less than 0.00. So, for example, ifpurchasesis 2000.00,getRewardsPercentage()returns 0.01, andcreditsUsedis 25.00, then this method must return 0.00.An
Accountholder can use the express line when the total purchases made by the member is greater than 1000.00.The
getRewardPercentage()method must return 0.01 (i.e., 1 percent) forAccountholders.The
increaseCreditsUsed()method must increase thecreditsUsedattribute by the given amount. It must never decrease thecreditsUsedattribute (i.e., it must do nothing when the parameter is negative).The
increasePurchases()method must increase thepurchasesattribute by the given amount. It must never decrease thepurchasesattribute (i.e., it must do nothing when the parameter is negative).The
purchase()method must process a purchase of the givenamount(when it is greater than 0.00), using as many credits as are available when theapplyCreditsparameter istrue(in which case it must invoke theincreaseCreditsUsed()method, passing it the appropriate value). It must invoke theincreasePurchases()method passing it the amount due (i.e., the amount of the purchase less any credits that are used), and must return the amount due. For example, if passed100.00andtruewhen theAccountholder has20.00credits available, it must pass20.00toincreaseCreditsUsed(), pass80.00toincreasePurchases()and must return80.00. The amount due must never be less than 0.00, but can be 0.00 (when enough credits are available). The credits used must never be greater than the purchase.The
toCSV()method must return aStringrepresentation of the purchases and credits used, formatted using a formatStringof"%.2f,%.2f".The
fromCSV()method must set the attributes of the owning object. It may assume that theStringit is passed was created by thetoCSV()method and must not do any error checking.The
toString()method must use return aStringrepresentation of the purchases, credits used, and available credit, formatted using a formatStringof"Purchases: %.2f\nCredits Used: %.2f\nCredits available: %.2f".
The VIPAccount Class
The VIPAccount class is an encapsulation of an exclusive membership
account at BBB. (“VIP” is an acronym for “very important person”.)
In addition to the specifications contained in the
UML class diagram, this class must conform to the following
specifications.
The
visitsattribute must keep track of the number of visits to BBB in which the member made a purchase.The default constructor must initialize all attributes to 0.00.
A
VIPAccountholder can use the express line whenever anAccountholder can. AVIPAccountholder can also use the express line when they have 10 or more visits.A
VIPAccountholder has the same starting reward percentage as anAccountholder, however, it can increase. Specifically, for every ten visits, aVIPAccountholder’s reward percentage increases by 0.01 up to a maximum of 0.15 (i.e., it can bever be larger than 15 percent). For example, aVIPAccountholder who has made 26 visits will have a reward percentage of 0.03 (i.e., 0.01 + 0.02) and aVIPAccountholder who has made 371 visits will have a reward percentage of 0.15.Each time the
increasePurchases()method is invoked, it must increase the number of visits by 1. Of course, it must also increase thepurchasesattribute in the base class.The
toCSV()must return aStringrepresentation of the result of invoking thetoCSV()method in the base class followed by the number of visits, formatted using a formatStringof"%s,%d".The
fromCSV()method must set all of the attributes of the owning object. It may assume that theStringit is passed was created by thetoCSV()method and must not do any error checking.The
toString()must return aStringrepresentation of the result of invoking thetoString()method in the base class followed by the number of visits, formatted using a formatStringof"%s\nVisits: %d".No method in the
VIPAccountclass may duplicate code in theAccountclass.
Unit Testing
You must write JUnit tests for all of your classes. Your JUnit test suite must cover all statements and all branches (as measured by EclEmma) in all of the classes you write. Your tests must be in a package named testing and each test class must include the word “Test” in its name.
As in the past, your unit tests of the input/output methods must make use of round-trip testing. So, you must create a JUnit test that first executes the appropriate write method and then executes the appropriate read method. Note that, to ensure that the write happens before the read, the two must be in the same JUnit test. You can (and should) have multiple tests of this kind, but each must be independent of the others.
Submission
You must submit (using Gradescope) a .zip file named pa2.zip
that contains:
CSVRepresentable.java,FileIdentifier.java,FileProcessor.java,CSVFileProcessor.java,Account.java, andVIPAccount.java; andYour JUnit tests
packaged appropriately. The io, membership, and testing directories/folders
must be at the top of the .zip file. (See the previous programming assignment if you
have forgotten how to do this.) Do not submit any .bbb files.
Your grade will be reduced by 5 points for each submission after the 10th submission. So, you should try to ensure that your code is correct before you submit it the first time. In other words, you should not use Gradescope to check your style, to test your code, or to ensure that your tests cover your code - you should do all of that on your computer before you make any submissions to Gradescope.
Note that your submission will not be graded if it does not comply with the specifications. So, if you do not complete a class your submission should include a stubbed-out version of it. This will allow you to potentially get credit for the methods/classes that you do complete.
Grading
Your code will first be graded by Gradescope and then by the Professor. The grade you receive from Gradescope is the maximum grade that you can receive on the assignment
Gradescope Grading
Your code must compile (in Gradescope, this will be indicated in the section on “Does your code compile?”) and all class names and method signatures must comply with the specifications (in Gradescope, this will be indicated in the section on “Do your class names, method signatures, etc. comply with the specifications?”) for you to receive any points on this assignment. Gradescope will then grade your submission as follows:
| Criterion | Points | Details |
|---|---|---|
| Conformance to the Style Guide | 0 | Success Required |
| Passing Your Tests | 10 | All or Nothing; Success Required |
| Coverage of Your Tests | 20 | Partial Credit Possible |
| Correctness | 70 | Partial Credit Possible |
As discussed above, your grade will be reduced by 5 points for each submission after the 10th submission. Gradescope will provide you with hints, but may not completely identify the defects in your submission.
Manual Grading
After the due date, the Professor may manually review your code. At this time, points may be deducted for code that does not conform to the specifications, inelegant code, duplicate code, inappropriate variable names, bad comments, etc.
Recommended Process
At this point in the semester, you should be able to create a good process and use it.
Questions to Think About
You don’t have to submit your answers to these questions, but you
should try to answer them because they will help you determine whether
or not you understand some of the important concepts covered in this
assignment. Note that you do not need the source code for the
CashRegister class to answer them.
Suppose you have a
CashRegisterclass in which acanUseExpressLine()message is sent to anObjectnamedmember, which is declared to be anAccountbut can actually be either anAccountor aVIPAccount. Both classes have such a method. What code is invoked and why?Suppose you have a
CashRegisterclass in which theavailableCredit()message is sent to anObjectnamedmember, which is declared to be anAccountbut can actually be either anAccountor aVIPAccount. The onlyavailableCredit()method is inAccount.javaso, obviously, that code will be invoked. However, thegetRewardPercentage()method is then invoked, and this method is implemented in both classes. What code will be invoked and why?Suppose you have a
CashRegisterclass in which thepurchase()message is sent to anObjectnamedmember, which is declared to be anAccountbut can actually be either anAccountor aVIPAccount. The onlypurchase()method is inAccount.javaso, obviously, that code will be invoked. However, theincreasePurchases()method is then invoked, and this method is implemented in both classes. What code will be invoked and why?Suppose you have a
CashRegisterclass that has an overloadedaddToLog()method, one which is passed anAccountand of which is passed aVIPAccount. Suppose further that this method is passed anObjectnamedmemberwhich is declared to be anAccountbut can actually be anAccountor aVIPAccount, both of which implement theCSVRepresentableinterface. Which overloaded version ofaddToLog()will be invoked and why?Why is the
FileProcessorclass declared to be abstract?Will the following fragment compile? Why or why not?
FileProcessor fp; fp = new CSVFileProcessor("temp.csv");In the previous programming assignment, the
iopackage was a subpackage of theproductpackage. In this assignment, theiopackage is not inside themembershippackage. Why not?