Program Description

This assignment will give you practice writing Java classes to a provided API and using Collections. You are to write a set of supporting classes for a simple shopping cart. The instructor has provided the Graphical User Interface (GUI) that will provide the "front end" or "view" to your program. You are to write the back end (what is often referred to as the "domain specific code" or the "model").

Here is a screen shot of what the program could look like when the user has selected various items to order (note that the exact appearance may be platform dependent): see image.

Prices are expressed as real numbers and quantities are expressed as integers (i.e., you can't buy 2.345 units of something). Notice that some of the items have a discount when you buy more. For example, Silly Putty normally costs $1.45 per unit, but you can buy 5 for $5.00. These items have, in effect, two prices: a single item price and a bulk item price for a bulk quantity. When computing the total with the bulk item discount, apply as many of the bulk quantity as you can and then use the single item price for any leftovers. For example, if the user is ordering 11 Silly Putty, then the first 10 are sold at the bulk price ($5.00 applied twice) and the one extra is charged at the single item price ($1.45) for a total of $11.45.

At the bottom of the GUI there is a checkbox for a discount for customers who have a store membership. If this box is checked, a 10% discount is applied to the total value of the ShoppingCart if that total value is greater than $15.00

For example, if we select that checkbox, the GUI looks like this: see image.

Implementation Guidelines

Your task is to implement the two classes that are used to make this code work:

  • Item
  • ShoppingCart

An Item object stores information about an individual item. It must have the following public methods. Note that the names (such as price and bulk quantity) given here are not meant to be the actual parameter names (Checkstyle would complain about them); they're meant to be descriptive.

Method Description
Item (name, price) Constructor that takes a name and a price as arguments. The name is a String and the price is a BigDecimal.
Item (name, price, bulk quantity, bulk price) Constructor that takes a name, a single-item price, a bulk quantity, and a bulk price as arguments. The name is a String, the quantity is an int and the prices are BigDecimals.
getName() Returns the name for this Item. (String return type)
getPrice() Returns the single item price for this Item. (BigDecimal return type)
getBulkQuantity() Returns the bulk quantity for this Item. (int return type)
getBulkPrice() Returns the bulk price for this Item. (BigDecimal return type)
isBulk() Returns True if the Item has bulk pricing; false otherwise
toString() Returns a String representation of this Item: name, followed by a comma and a space, followed by price. If the item has a bulk price, you should append an extra space and a parenthesized description of the bulk pricing that has the bulk quantity, the word "for" and the bulk price. See the examples below.
equals (object) Returns true if the specified object is equivalent to this Item, and false otherwise. Two items are equivalent if they have exactly equivalent names, prices, bulk quantities and bulk prices. This method must properly override java.lang.Object.equals().
hashCode() Returns an integer hash code for this item. This method must override java.lang.Object.hashCode() and be consistent with equals().

The String representation of an Item must exactly match that shown in the screenshots. For example, an Item named "X" with a per-item price of $19.99 and no bulk quantity would have the String representation X, $19.99 (without the quotes); an item named X with a per-item price of $19.99, a bulk quantity of 5, and a bulk price of $89.99 would have the String representation X, $19.99 (5 for $89.99) (without the quotes). The format of these String representations will be tested.

A ShoppingCart object stores information about the customer's overall purchase. One field must be a collection to hold information about all the Items the customer has ordered. (Use a generic collection from the Java Collections Framework. One possible choice is Map< Item, Integer >).

The ShoppingCart class must have the following public methods.

Method Description
ShoppingCart() Constructor that creates an empty shopping cart.
add (Item, quantity) Adds an order to the shopping cart, replacing any previous order for an equivalent Item with the new order. The parameters are an Item and an int. The int represents the quantity of the Item to add to the cart. The return type of this method is void
setMembership (value) Sets whether or not the customer for this shopping cart has a store membership (the parameter is a boolean; true means the customer has a membership, false means the customer doesn't). The return is void.
calculateTotal() Returns the total cost of this shopping cart as a BigDecimal. This returned BigDecimal should have scale of 2 and use RoundingMode. HALF_EVEN
clear() Removes all orders from the cart. The return is void.

You must not change any method signatures or return types defined in this assignment. (You may change parameter names but not parameter data types.) You must not introduce any other non-private methods to these classes, although you may add your own private helper methods. You may override toString in ShoppingCart class (you may find this helpful for testing and debugging). You are also allowed to override other (non-final) methods declared in java.lang.Object, such as equals and hashCode. If you do, however, your definitions must be reasonable and consistent with each other; if you implement inconsistent equals and hashCode methods, you will certainly lose points. You must override toString, equals and hashCode for the Item class, as described above.

Starter Code

items.txt

Silly Putty;1.45;5;5.00
'Java Rules!' button;0.75;10;5.00
'Java Rules!' bumper sticker;1.20;10;10.00
Computer science pen;2.00
Rubik's Cube;10.00
Mp3, Mp4, FM Music Player;20.00
Arduino Uno Ultimate Starter Kit;55.00
LEGO Mindstorms EV3;350.00
Xbox One X;620.00
PlayStation 5;750.00
64 inch OLED TV;2000.00

Item.java

// Finish and comment me!

package model;

import java.math.BigDecimal;

public final class Item {

// Add whatever fields you think are necessary.


public Item(final String theName, final BigDecimal thePrice) {

}


public Item(final String theName, final BigDecimal thePrice,
final int theBulkQuantity, final BigDecimal theBulkPrice) {

}


public String getName() {

return null;
}

public BigDecimal getPrice() {

return null;
}


public int getBulkQuantity() {

return 0;
}


public BigDecimal getBulkPrice() {

return null;
}


public boolean isBulk() {

return false;
}

@Override
public String toString() {

return null;
}


@Override
public boolean equals(final Object theOther) {

return false;
}


@Override
public int hashCode() {

return 0;
}

}

ShoppingCart.java

// Finish and comment me!

package model;

import java.math.BigDecimal;

public class ShoppingCart {

// Add whatever fields you think are necessary.


public ShoppingCart() {

}


public void add(final Item theItem, final int theQuantity) {

}


public void setMembership(final boolean theMembership) {

}


public BigDecimal calculateTotal() {

return null;
}

public void clear() {

}

}

FileLoader.java

package utility;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Paths;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
import model.Item;

public final class FileLoader {

/**
* A private constructor, to prevent external instantiation.
*/
private FileLoader() {

}

/**
* Reads item information from a file and returns a List of Item objects.
* @param theFile the name of the file to load into a List of Items
* @return a List of Item objects created from data in an input file
*/
public static List< Item > readItemsFromFile(final String theFile) {
final List< Item > items = new LinkedList< >();

try (Scanner input = new Scanner(Paths.get(theFile))) { // Java 7!
while (input.hasNextLine()) {
try (Scanner line = new Scanner(input.nextLine())) {
line.useDelimiter(";");
final String itemName = line.next();
final BigDecimal itemPrice = line.nextBigDecimal();
if (line.hasNext()) {
final int bulkQuantity = line.nextInt();
final BigDecimal bulkPrice = line.nextBigDecimal();
items.add(new Item(itemName, itemPrice, bulkQuantity, bulkPrice));
} else {
items.add(new Item(itemName, itemPrice));
}
}
}
} catch (final IOException e) {
e.printStackTrace();
} // no finally block needed to close 'input' with the Java 7 'try with resource' block

return items;
}

/**
* Reads item information from a file and returns a List of Item objects.
* @param theFile the name of the file to load into a List of Items
* @return a List of Item objects created from data in an input file
*/
public static List< String > readConfigurationFromFile(final String theFile) {
final List< String > results = new LinkedList< >();

try (Scanner input = new Scanner(Paths.get(theFile))) { // Java 7!
while (input.hasNextLine()) {
final String line = input.nextLine();

//if (!line.startsWith("#")) {
if (!(line.charAt(0) == '#')) {
results.add(line);
}

}
} catch (final IOException e) {
e.printStackTrace();
} // no finally block needed to close 'input' with the Java 7 try with resource block

return results;
}
}

ShoppingFrame.java

package view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.text.NumberFormat;
import java.util.LinkedList;
import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import model.Item;
import model.ShoppingCart;

/**
* ShoppingFrame provides the user interface for a shopping cart program.
*/
public final class ShoppingFrame extends JFrame {

/** A generated serialization id. */
private static final long serialVersionUID = 4479585442295889730L;

// constants to capture screen dimensions
/** A ToolKit. */
private static final Toolkit KIT = Toolkit.getDefaultToolkit();

/** The Dimension of the screen. */
private static final Dimension SCREEN_SIZE = KIT.getScreenSize();

/** The width of the text field in the GUI. */
private static final int TEXT_FIELD_WIDTH = 12;

/*
* For the UW color palette and other UW branding information see
* http://www.washington.edu/brand/graphic-elements/primary-color-palette/
*/

/**
* The color for some elements in the GUI.
*/
private static final Color UW_GOLD = new Color(232, 211, 162);

/**
* The color for some elements in the GUI.
*/
private static final Color UW_PURPLE = new Color(51, 0, 111);

/**
* The shopping cart used by this GUI.
*/
private final ShoppingCart myItems;

/**
* The list that stores the inventory.
*/
private final List< Item > myInventory;

/**
* The text field used to display the total amount owed by the customer.
*/
private final JTextField myTotal;

/**
* A List of the item text fields.
*/
private final List< JTextField > myQuantities;

/**
* Initializes the shopping cart GUI.
*
* @param theInventory The list of Items.
*/
public ShoppingFrame(final List< Item > theInventory) {

super(); // No title on the JFrame. We can set this later.

myItems = new ShoppingCart();

// set up text field with order total
myTotal = new JTextField("$0.00", TEXT_FIELD_WIDTH);

myQuantities = new LinkedList< >();

myInventory = theInventory;
setupGUI();
}

/**
* Setup the various parts of the GUI.
*/
private void setupGUI() {

// replace the default JFrame icon
final ImageIcon img = new ImageIcon("files/w.gif");
setIconImage(img.getImage());

setTitle("Shopping Cart");

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

add(makeTotalPanel(), BorderLayout.NORTH);

final JPanel itemsPanel = makeItemsPanel(myInventory);
add(itemsPanel, BorderLayout.CENTER);

add(makeCheckBoxPanel(), BorderLayout.SOUTH);

// adjust size to just fit
pack();

// make the GUI so that it cannot be resized by the user dragging a corner
setResizable(false);

// position the frame in the center of the screen
setLocation(SCREEN_SIZE.width / 2 - getWidth() / 2,
SCREEN_SIZE.height / 2 - getHeight() / 2);
setVisible(true);
}


/**
* Creates a panel to hold the total.
*
* @return The created panel
*/
private JPanel makeTotalPanel() {
// tweak the text field so that users can't edit it, and set
// its color appropriately

myTotal.setEditable(false);
myTotal.setEnabled(false);
myTotal.setDisabledTextColor(Color.BLACK);

// create the panel, and its label

final JPanel totalPanel = new JPanel();
totalPanel.setBackground(UW_PURPLE);
final JLabel l = new JLabel("order total");
l.setForeground(Color.WHITE);
totalPanel.add(l);
totalPanel.add(myTotal);

final JPanel p = new JPanel(new BorderLayout());
p.add(totalPanel, BorderLayout.CENTER);

return p;
}

/**
* Creates a panel to hold the specified list of items.
*
* @param theItems The items
* @return The created panel
*/
private JPanel makeItemsPanel(final List< Item > theItems) {
final JPanel p = new JPanel(new GridLayout(theItems.size(), 1));

for (final Item item : theItems) {
addItem(item, p);
}

return p;
}

/**
* Creates and returns the checkbox panel.
*
* @return the checkbox panel
*/
private JPanel makeCheckBoxPanel() {
final JPanel p = new JPanel();
p.setBackground(UW_PURPLE);

final JButton clearButton = new JButton("Clear");
clearButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent theEvent) {
myItems.clear();
for (final JTextField field : myQuantities) {
field.setText("");
}
updateTotal();
}
});
p.add(clearButton);

final JCheckBox cb = new JCheckBox("customer has store membership");
cb.setForeground(Color.WHITE);
cb.setBackground(UW_PURPLE);
cb.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent theEvent) {
myItems.setMembership(cb.isSelected());
updateTotal();
}
});
p.add(cb);

return p;
}

/**
* Adds the specified product to the specified panel.
*
* @param theItem The product to add.
* @param thePanel The panel to add the product to.
*/
private void addItem(final Item theItem, final JPanel thePanel) {
final JPanel sub = new JPanel(new FlowLayout(FlowLayout.LEFT));
sub.setBackground(UW_GOLD);
final JTextField quantity = new JTextField(3);
myQuantities.add(quantity);
quantity.setHorizontalAlignment(SwingConstants.CENTER);
quantity.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent theEvent) {
quantity.transferFocus();
}
});
quantity.addFocusListener(new FocusAdapter() {
@Override
public void focusLost(final FocusEvent theEvent) {
updateItem(theItem, quantity);
}
});
sub.add(quantity);
final JLabel l = new JLabel(theItem.toString());
l.setForeground(UW_PURPLE);
sub.add(l);
thePanel.add(sub);
}

/**
* Updates the set of items by changing the quantity of the specified
* product to the specified quantity.
*
* @param theItem The product to update.
* @param theQuantity The new quantity.
*/
private void updateItem(final Item theItem, final JTextField theQuantity) {
final String text = theQuantity.getText().trim();
int number = 0;
try {
number = Integer.parseInt(text);
if (number < 0) {
// disallow negative numbers
throw new NumberFormatException();
}
} catch (final NumberFormatException e) {
number = 0;
theQuantity.setText("");
}
myItems.add(theItem, number);
updateTotal();
}

/**
* Updates the total displayed in the window.
*/
private void updateTotal() {
final double total = myItems.calculateTotal().doubleValue();
myTotal.setText(NumberFormat.getCurrencyInstance().format(total));
}
}

// end of class ShoppingFrame

ShoppingMain.java

package view;

import java.awt.EventQueue;
import utility.FileLoader;

/**
* ShoppingMain provides the main method for a simple shopping cart GUI.
*/

public final class ShoppingMain {

/**
* The path and name of the inventory file.
*/
private static final String INVENTORY_FILE = "files/items.txt";

/**
* A private constructor, to prevent external instantiation.
*/
private ShoppingMain() {
}

/**
* The main() method - displays and runs the shopping cart GUI.
*
* @param theArgs Command line arguments, ignored by this program.
*/
public static void main(final String... theArgs) {

EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new ShoppingFrame(FileLoader.readItemsFromFile(INVENTORY_FILE));
}
});
} // end main()

} // end class ShoppingMain
Academic Honesty!
It is not our intention to break the school's academic policy. Posted solutions are meant to be used as a reference and should not be submitted as is. We are not held liable for any misuse of the solutions. Please see the frequently asked questions page for further questions and inquiries.
Kindly complete the form. Please provide a valid email address and we will get back to you within 24 hours. Payment is through PayPal, Buy me a Coffee or Cryptocurrency. We are a nonprofit organization however we need funds to keep this organization operating and to be able to complete our research and development projects.