HW8: Big Box Bargains¶

Learning Objectives¶
- Implement interfaces and abstract classes, and apply the concept of specialization
- Demonstrate understanding of polymorphism, including dynamic and static binding.
- Apply knowledge 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.
Starter Code¶
The following zip file contains the starter code, which includes provided classes, sample JUnit test files, and classes with method stubs that you need to implement.
Starter Code Is Incomplete
We're giving you partially completed code stubs to help save time on typing and writing documentation comments. However, some important parts are missing. You’ll need to carefully review all the provided code alongside the UML diagram to fix any mistakes and fill in what's missing.
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. The provided classes are outlined in red. Be sure not to edit those classes.

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).
Note
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:
the fromCSV() 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, provided, do not edit¶
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, provided, do not edit¶
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
encrypt()method takes a string as parameter and returns an encrypted version by shifting each character forward using a fixed key value (KEY). It does this by addingKEYto the Unicode value of each character.
-
The
decrypt()method reverses the encryption by shifting each character in the parameter backward using the same fixed key value (KEY) used in theencrypt()method. -
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 need to test your code using JUnit. Sample JUnit tests have been provided to help you get started, and you are encouraged to expand and build upon them.
Submission¶
- You must submit (using Gradescope)
FileProcessor.java,CSVFileProcessor.java,Account.java, andVIPAccount.java. - Do not submit JUnit tests or provided
CSVRepresentable.java,FileIdentifier.java. - Do not submit any
.bbbfiles.
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.
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 |
| Correctness | 100 | 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?