【实验】异常和IO在Gourmet咖啡系统中的应用
前尘往事
面向对象设计、UML建模与基本的Java面向对象编程实现
实验一:设计模式在Gourmet咖啡系统中的应用
Using File I/O in the Gourmet Coffee System
Prerequisites, Goals, and Outcomes
Prerequisites: Before you begin this exercise, you need mastery of the following:
- Java API
- Knowledge of the class StringTokenizer
- File I/O
- Knowledge of file I/O
- How to read data from a file
- How to write data to a file
- Knowledge of file I/O
Goals: Reinforce your ability to use file I/O
Outcomes: You will master the following skills:
- Produce applications that read data from a file and parse it
- Produce applications that write data to a file
Background
In this assignment, you will create another version of the Gourmet Coffee System. In previous versions, the data for the product catalog was hard-coded in the application. In this version, the data will be loaded from a file. Also, the user will be able to write the sales information to a file in one of three formats: plain text, HTML, or XML. Part of the work has been done for you and is provided in the student archive. You will implement the code that loads the product catalog and persists the sales information.
Description
The Gourmet Coffee System sells three types of products: coffee, coffee brewers, and accessories for coffee consumption. A file called catalog.dat stores the product data:
- catalog.dat. File with product data
Every line in catalog.dat contains exactly one product.
A line for a coffee product has the following format:Coffee_code_description_price_origin_roast_flavor_aroma_acidity_body
where:
- “Coffee” is a prefix that indicates the line type.
- code is a string that represents the code of the coffee.
- description is a string that represents the description of the coffee.
- price is a double that represents the price of the coffee.
- origin is a string that represents the origin of the coffee.
- roast is a string that represents the roast of the coffee.
- flavor is a string that represents the flavor of the coffee.
- aroma is a string that represents the aroma of the coffee.
- acidity is a string that represents the acidity of the coffee.
- body is a string that represents the body of the coffee.
The fields are delimited by an underscore ( _ ). You can assume that the fields themselves do not contain any underscores.
A line for a coffee brewer has the following format:Brewer_code_description_price_model_waterSupply_numberOfCups
where:
- “Brewer” is a prefix that indicates the line type.
- code is a string that represents the code of the brewer.
- description is a string that represents the description of the brewer.
- price is a double that represents the price of the brewer.
- model is a string that represents the model of the coffee brewer.
- waterSupply is a string that represents the water supply of the coffee brewer.
- numberOfCups is an integer that represents the capacity of the coffee brewer in number of cups.
The fields are delimited by an underscore ( _ ). You can assume that the fields themselves do not contain any underscores.
A line for a coffee accessory has the following format:Product_code_description_price
where:
- “Product” is a prefix that indicates the line type.
- code is a string that represents the code of the product.
- description is a string that represents the description of the product.
- price is a double that represents the price of the product.
The fields are delimited by an underscore ( _ ). You can assume that the fields themselves do not contain any underscores.
The following class diagram highlights the elements you will use to load the product catalog and persist the sales information:
Figure 1 Portion of Gourmet Coffee System class diagram
In this assignment, you will implement FileCatalogloader and complete the implementation of GourmetCoffee.
Interface CatalogLoader
The interface CatalogLoader declares a method for producing a product catalog. A complete implementation of this interface is provided in the student archive.
Method:
- Catalog loadCatalog(String fileName) throws FileNotFoundException, IOException, DataFormatException
Loads the information in the specified file into a product catalog and returns the catalog.
Class DataFormatException
This exception is thrown when a line in the file being parsed has errors:
- The line does not have the expected number of tokens.
- The tokens that should contain numbers do not.
A complete implementation of this class is provided in the student archive.
Class FileCatalogLoader
The class FileCatalogLoader implements interface CatalogLoader. It is used to obtain a product catalog from a file. You should implement this class from scratch:
Methods:
-
private Product readProduct(String line) throws DataFormatException
This method reads a line of coffee-accessory data. It uses the class StringTokenizer to extract the accessory data in the specified line. If the line is error free, this method returns a Product object that encapsulates the accessory data. If the line has errors, that is, if it does not have the expected number of tokens or the token that should contain a double does not; this method throws a DataFormatException that contains the line of malformed data. -
private Coffee readCoffee(String line) throws DataFormatException
This method reads a line of coffee data. It uses the class StringTokenizer to extract the coffee data in the specified line. If the line is error free, this method returns a Coffee object that encapsulates the coffee data. If the line has errors, that is, if it does not have the expected number of tokens or the token that should contain a double does not; this method throws a DataFormatException that contains the line of malformed data. -
private CoffeeBrewer readCoffeeBrewer(String line) throws DataFormatException
This method reads a line of coffee-brewer data. It uses the class StringTokenizer to extract the brewer data in the specified line. If the line is error free, this method returns a CoffeeBrewer object that encapsulates the brewer data. If the line has errors, that is, if it does not have the expected number of tokens or the tokens that should contain a number do not; this method throws a DataFormatException that contains the line of malformed data. -
public Catalog loadCatalog(String filename) throws FileNotFoundException, IOException, DataFormatException
This method loads the information in the specified file into a product catalog and returns the catalog. It begins by opening the file for reading. It then proceeds to read and process each line in the file. The method String.startsWith is used to determine the line type:- If the line type is “Product”, the method readProduct is invoked.
- If the line type is “Coffee”, the method readCoffee is invoked.
- If the line type is “Brewer”, the method readCoffeeBrewer is invoked.
After the line is processed, loadCatalog adds the product (accessory, coffee, or brewer) to the product catalog. When all the lines in the file have been processed, load returns the product catalog to the calling method.
This method can throw the following exceptions:- FileNotFoundException — if the specified file does not exist.
- IOException — if there is an error reading the information in the specified file.
- DataFormatException — if a line in the file has errors (the exception should contain the line of malformed data).
Class GourmetCoffee
A partial implementation of class GourmetCoffee is provided in the student archive. You should implement writeFile, a method that writes sales information to a file:
- private void writeFile(String fileName, String content) throws IOException
This method creates a new file with the specified name, writes the specified string to the file, and then closes the file.
Class TestFileCatalogLoader
This class is a test driver for FileCatalogLoader. A complete implementation is included in the student archive student-files.zip. You should use this class to test your implementation of FileCatalogLoader.
Files
The following files are needed to complete this assignment:
-
student-files.zip — Download this file. This archive contains the following:
-
Class files
- Coffee.class
- CoffeeBrewer.class
- Product.class
- Catalog.class
- OrderItem.class
- Order.class
- Sales.class
- SalesFormatter.class
- PlainTextSalesFormatter.class
- HTMLSalesFormatter.class
- XMLSalesFormatter.class
-
Documentation
- Coffee.html
- CoffeeBrewer.html
- Product.html
- Catalog.html
- OrderItem.html
- Order.html
- Sales.html
- SalesFormatter.html
- PlainTextSalesFormatter.html
- HTMLSalesFormatter.html
- XMLSalesFormatter.html
-
Java files
- CatalogLoader.java: A complete implementation
- DataFormatException.java: A complete implementation
- TestFileCatalogLoader.java: A complete implementation
- GourmetCoffee.java: Use this template to complete your implementation.
-
Data files for the test driver
- catalog.dat: A file with product information
- empty.dat: An empty file
-
Class files
Tasks
Implement the class FileCatalogLoader and the method GourmetCoffee.writeFile. Document using Javadoc and follow Sun’s code conventions. The following steps will guide you through this assignment. Work incrementally and test each increment. Save often.
-
Extract the files by issuing the following command at the command prompt:
C:>unzip student-files.zip -
Then, implement class FileCatalogLoader from scratch. Use the TestFileCatalogLoader driver to test your implementation.
-
Next, implement the method GourmetCoffee.writeFile.
-
Finally, compile the class GourmetCoffee, and execute the class GourmetCoffee by issuing the following command at the command prompt:
C:>java GourmetCoffee catalog.dat
Sales information has been hard-coded in the GourmetCoffee template provided by iCarnegie. -
If the user displays the catalog, the output should be:
C001 Colombia, Whole, 1 lb
C002 Colombia, Ground, 1 lb
C003 Italian Roast, Whole, 1 lb
C004 Italian Roast, Ground, 1 lb
C005 French Roast, Whole, 1 lb
C006 French Roast, Ground, 1 lb
C007 Guatemala, Whole, 1 lb
C008 Guatemala, Ground, 1 lb
C009 Sumatra, Whole, 1 lb
C010 Sumatra, Ground, 1 lb
C011 Decaf Blend, Whole, 1 lb
C012 Decaf Blend, Ground, 1 lb
B001 Home Coffee Brewer
B002 Coffee Brewer, 2 Warmers
B003 Coffee Brewer, 3 Warmers
B004 Commercial Coffee, 20 Cups
B005 Commercial Coffee, 40 Cups
A001 Almond Flavored Syrup
A002 Irish Creme Flavored Syrup
A003 Mint Flavored syrup
A004 Caramel Flavored Syrup
A005 Gourmet Coffee Cookies
A006 Gourmet Coffee Travel Thermo
A007 Gourmet Coffee Ceramic Mug
A008 Gourmet Coffee 12 Cup Filters
A009 Gourmet Coffee 36 Cup Filters -
If the user saves the sales information in plain text, a file with the following content should be created:
------------------------
Order 1
5 C001 17.99
Total = 89.94999999999999
------------------------
Order 2
2 C002 18.75
2 A001 9.0
Total = 55.5
------------------------
Order 3
1 B002 200.0
Total = 200.0
- If the user saves the sales information in HTML, a file with the following content should be created:
<html>
<body>
<center><h2>Orders</h2></center>
<hr>
<h4>Total = 89.94999999999999</h4>
<p>
<b>code:</b> C001<br>
<b>quantity:</b> 5<br>
<b>price:</b> 17.99
</p>
<hr>
<h4>Total = 55.5</h4>
<p>
<b>code:</b> C002<br>
<b>quantity:</b> 2<br>
<b>price:</b> 18.75
</p>
<p>
<b>code:</b> A001<br>
<b>quantity:</b> 2<br>
<b>price:</b> 9.0
</p>
<hr>
<h4>Total = 200.0</h4>
<p>
<b>code:</b> B002<br>
<b>quantity:</b> 1<br>
<b>price:</b> 200.0
</p>
</body>
</html>
- If the user saves the sales information in XML, a file with the following content should be created:
<Sales>
<Order total="89.94999999999999">
<OrderItem quantity="5" price="17.99">C001</OrderItem>
</Order>
<Order total="55.5">
<OrderItem quantity="2" price="18.75">C002</OrderItem>
<OrderItem quantity="2" price="9.0">A001</OrderItem>
</Order>
<Order total="200.0">
<OrderItem quantity="1" price="200.0">B002</OrderItem>
</Order>
</Sales>
Submission
Upon completion, submit only the following:
- FileCatalogLoader.java
- GourmetCoffee.java
提供的.class文件
这真是不可描述。。。
下面的代码是****←_←反编译得到的.java,eclipse装插件、idea自身都可以支持简单不加密的****。
反编译出来的还是比较low的,比如泛型啥的都没有啊!
Product类
public class Product {
private String code;
private String description;
private double price;
public Product(String var1, String var2, double var3) {
this.code = var1;
this.description = var2;
this.price = var3;
}
public String getCode() {
return this.code;
}
public String getDescription() {
return this.description;
}
public double getPrice() {
return this.price;
}
public boolean equals(Object var1) {
return var1 instanceof Product && this.getCode().equals(((Product)var1).getCode());
}
public String toString() {
return this.getCode() + "_" + this.getDescription() + "_" + this.getPrice();
}
}
Coffee类
public class Coffee extends Product {
private String origin;
private String roast;
private String flavor;
private String aroma;
private String acidity;
private String body;
public Coffee(String var1, String var2, double var3, String var5, String var6, String var7, String var8, String var9, String var10) {
super(var1, var2, var3);
this.origin = var5;
this.roast = var6;
this.flavor = var7;
this.aroma = var8;
this.acidity = var9;
this.body = var10;
}
public String getOrigin() {
return this.origin;
}
public String getRoast() {
return this.roast;
}
public String getFlavor() {
return this.flavor;
}
public String getAroma() {
return this.aroma;
}
public String getAcidity() {
return this.acidity;
}
public String getBody() {
return this.body;
}
public String toString() {
return super.toString() + "_" + this.getOrigin() + "_" + this.getRoast() + "_" + this.getFlavor() + "_" + this.getAroma() + "_" + this.getAcidity() + "_" + this.getBody();
}
}
CoffeeBrewer类
public class CoffeeBrewer extends Product {
private String model;
private String waterSupply;
private int numberOfCups;
public CoffeeBrewer(String var1, String var2, double var3, String var5, String var6, int var7) {
super(var1, var2, var3);
this.model = var5;
this.waterSupply = var6;
this.numberOfCups = var7;
}
public String getModel() {
return this.model;
}
public String getWaterSupply() {
return this.waterSupply;
}
public int getNumberOfCups() {
return this.numberOfCups;
}
public String toString() {
return super.toString() + "_" + this.getModel() + "_" + this.getWaterSupply() + "_" + this.getNumberOfCups();
}
}
OrderItem类
public class OrderItem {
private Product product;
private int quantity;
public OrderItem(Product var1, int var2) {
this.product = var1;
this.quantity = var2;
}
public Product getProduct() {
return this.product;
}
public int getQuantity() {
return this.quantity;
}
public void setQuantity(int var1) {
this.quantity = var1;
}
public double getValue() {
return this.getProduct().getPrice() * (double)this.getQuantity();
}
public String toString() {
return this.getQuantity() + " " + this.getProduct().getCode() + " " + this.getProduct().getPrice();
}
}
Order类
import java.util.ArrayList;
import java.util.Iterator;
public class Order implements Iterable<OrderItem> {
private ArrayList<OrderItem> items = new ArrayList<>();
public Order() {
}
public void addItem(OrderItem var1) {
this.items.add(var1);
}
public void removeItem(OrderItem var1) {
this.items.remove(var1);
}
public Iterator<OrderItem> iterator() {
return this.items.iterator();
}
public OrderItem getItem(Product var1) {
Iterator var2 = this.items.iterator();
OrderItem var3;
do {
if (!var2.hasNext()) {
return null;
}
var3 = (OrderItem)var2.next();
} while(!var3.getProduct().equals(var1));
return var3;
}
public int getNumberOfItems() {
return this.items.size();
}
public double getTotalCost() {
double var1 = 0.0D;
OrderItem var4;
for(Iterator var3 = this.items.iterator(); var3.hasNext(); var1 += var4.getValue()) {
var4 = (OrderItem)var3.next();
}
return var1;
}
}
Catalog类
import java.util.ArrayList;
import java.util.Iterator;
public class Catalog implements Iterable<Product> {
private ArrayList<Product> products = new ArrayList<>();
public Catalog() {
}
public void addProduct(Product var1) {
this.products.add(var1);
}
public Iterator<Product> iterator() {
return this.products.iterator();
}
public Product getProduct(String var1) {
Iterator var2 = this.products.iterator();
Product var3;
do {
if (!var2.hasNext()) {
return null;
}
var3 = (Product)var2.next();
} while(!var3.getCode().equals(var1));
return var3;
}
public int getNumberOfProducts() {
return this.products.size();
}
}
Sales类
import java.util.ArrayList;
import java.util.Iterator;
public class Sales implements Iterable<Order> {
private ArrayList<Order> orders = new ArrayList<>();
public Sales() {
}
public void addOrder(Order var1) {
this.orders.add(var1);
}
public Iterator<Order> iterator() {
return this.orders.iterator();
}
public int getNumberOfOrders() {
return this.orders.size();
}
}
SalesFormatter类
public interface SalesFormatter {
//Produces a string representation of the sales information.
public abstract String formatSales(Sales sales);
}
PlainTextSalesFormatter类
import java.util.Iterator;
public class PlainTextSalesFormatter implements SalesFormatter {
private static PlainTextSalesFormatter singletonInstance;
private PlainTextSalesFormatter() {
}
public static synchronized PlainTextSalesFormatter getSingletonInstance() {
if (singletonInstance == null)
singletonInstance = new PlainTextSalesFormatter();
return singletonInstance;
}
public String formatSales(Sales sales) {
String string = "";
int i = 1;
Iterator<Order> iterator1 = sales.iterator();
while(iterator1.hasNext()) {
Order order = iterator1.next();
string +="---------------------\r\n";
string += "Order " + i + "\r\n\r\n";
Iterator<OrderItem> iterator2 = order.iterator();
while(iterator2.hasNext()) {
OrderItem orderItem = iterator2.next();
string += orderItem.getQuantity() + " " + orderItem.getProduct().getCode() + " " +orderItem.getProduct().getPrice() + "\r\n";
}
i++;
string += "\r\n" + "Total = " + order.getTotalCost() + "\r\n";
}
return string;
}
}
HTMLSalesFormatter类
import java.util.Iterator;
public class HTMLSalesFormatter implements SalesFormatter {
private static HTMLSalesFormatter singletonInstance;
private HTMLSalesFormatter() {
}
public static synchronized HTMLSalesFormatter getSingletonInstance() {
if (singletonInstance == null)
singletonInstance = new HTMLSalesFormatter();
return singletonInstance;
}
public String formatSales(Sales sales) {
String string = "";
string +="<html>\r\n <body>\r\n <center><h2>Orders</h2></center>\r\n";
Iterator<Order> iterator1 = sales.iterator();
while(iterator1.hasNext()) {
Order order = iterator1.next();
string += " <hr>\r\n <h4>Total = " + order.getTotalCost() + "</h4>\r\n <p>\r\n";
Iterator<OrderItem> iterator2 = order.iterator();
while(iterator2.hasNext()) {
OrderItem orderItem = iterator2.next();
string += " <b>code:</b> "+orderItem.getProduct().getCode()+"<br>\r\n" + " <b>quantity:</b> "+orderItem.getQuantity()+"<br>\r\n"+" <b>price:</b> "+orderItem.getProduct().getPrice()+"\r\n";
}
string += " </p>\r\n";
}
string += " </body>\r\n</html>\r\n";
return string;
}
}
XMLSalesFormatter类
import java.util.Iterator;
public class XMLSalesFormatter implements SalesFormatter {
private static XMLSalesFormatter singletonInstance;
private XMLSalesFormatter() {
}
public static synchronized XMLSalesFormatter getSingletonInstance() {
if (singletonInstance == null)
singletonInstance = new XMLSalesFormatter();
return singletonInstance;
}
public String formatSales(Sales sales) {
String string = "";
string +="<Sales>\r\n";
Iterator<Order> iterator1 = sales.iterator();
while(iterator1.hasNext()) {
Order order = iterator1.next();
string += " <Order total=\""+order.getTotalCost()+"\">\r\n";
Iterator<OrderItem> iterator2 = order.iterator();
while(iterator2.hasNext()) {
OrderItem orderItem = iterator2.next();
string += " <OrderItem quantity=\""+orderItem.getQuantity()+"\" price=\""+orderItem.getProduct().getPrice()+"\">"+orderItem.getProduct().getCode()+"</OrderItem>\r\n";
}
string += " </Order>\r\n";
}
string += "</Sales>\r\n";
return string;
}
}
Code
DataFormatException类
public class DataFormatException extends Exception {
//序列化
private static final long serialVersionUID = 1L;
/**
* Constructs a <code>DataFormatException</code> with no detail
* message.
*/
public DataFormatException() {
}
/**
* Constructs a <code>DataFormatException</code> with the
* specified detail message.
*
* @param message the malformed data
*/
public DataFormatException(String message) {
super(message);
}
}
CatalogLoader类
import java.io.*;
/**
* This interface declares a method for obtaining a products catalog.
*
* @author BlankSpace
* @version 1.1.0
* @see Catalog
*/
public interface CatalogLoader {
/*
* Loads the product catalog with the data in the specified file.
*
* @param filename The name of a file that contains catalog
* information.
* @return the product catalog.
* @throws FileNotFoundException if the specified file does not
* exist.
* @throws IOException if there is an error reading the
* information in the specified file.
* @throws DataFormatException if the file contains
* badly-formed data.
*/
Catalog loadCatalog(String fileName)
throws FileNotFoundException, IOException, DataFormatException;
}
FileCatalogLoader类
import java.util.StringTokenizer;
import java.io.*;
/**
* This class implements interface CatalogLoader. It is used to obtain a product catalog from a file.
*
* @author BlankSpace
* @version 1.0.0
* @see DataFormatException
*/
public class FileCatalogLoader implements CatalogLoader {
private final String split = "_";
/**
* This method reads a line of coffee-accessory data.
* It uses the class StringTokenizer to extract the accessory data in the specified line.
* If the line is error free, this method returns a Product object that encapsulates the accessory data.
* If the line has errors, that is, if it does not have the expected number of tokens or the token that should contain a double does not.
* This method throws a DataFormatException that contains the line of malformed data.
* @param line
* @return an new object of Coffee
* @throws DataFormatException, which contains the line of malformed data
*/
private Product readProduct(String line) throws DataFormatException {
String code = null;
String description = null;
double price = 0.0;
StringTokenizer token = new StringTokenizer(line, split);
while (token.hasMoreTokens()) {
token.nextToken();
code = token.nextToken();
description = token.nextToken();
price = Double.parseDouble(token.nextToken());
}
return new Product(code, description, price);
}
/**
* This method reads a line of coffee data. It uses the class StringTokenizer to extract the coffee data in the specified line.
* If the line is error free, this method returns a Coffee object that encapsulates the coffee data.
* If the line has errors, that is, if it does not have the expected number of tokens or the token that should contain a double does not.
* This method throws a DataFormatException that contains the line of malformed data.
* @param line
* @return an new object of Coffee
* @throws DataFormatException, which contains the line of malformed data
*/
private Coffee readCoffee(String line) throws DataFormatException {
String code = null;
String description = null;
double price = 0.0;
String origin = null;
String roast = null;
String flavor = null;
String aroma = null;
String acidity = null;
String body = null;
StringTokenizer token = new StringTokenizer(line, split);
while (token.hasMoreTokens()) {
token.nextToken();
code = token.nextToken();
description = token.nextToken();
price = Double.parseDouble(token.nextToken());
origin = token.nextToken();
roast = token.nextToken();
flavor = token.nextToken();
aroma = token.nextToken();
acidity = token.nextToken();
body = token.nextToken();
}
return new Coffee(code, description, price, origin, roast, flavor, aroma, acidity, body);
}
/**
* This method reads a line of coffee-brewer data.
* It uses the class StringTokenizer to extract the brewer data in the specified line.
* If the line is error free, this method returns a CoffeeBrewer object that encapsulates the brewer data.
* If the line has errors, that is, if it does not have the expected number of tokens or the tokens that should contain a number do not.
* This method throws a DataFormatException that contains the line of malformed data.
* @param line
* @return an new object of Coffee
* @throws DataFormatException, which contains the line of malformed data
*/
private CoffeeBrewer readCoffeeBrewer(String line) throws DataFormatException {
String code = null;
String description = null;
double price = 0.0;
String model = null;
String waterSupply = null;
int numberOfCups = 0;
StringTokenizer token = new StringTokenizer(line, split);
while (token.hasMoreTokens()) {
token.nextToken();
code = token.nextToken();
description = token.nextToken();
price = Double.parseDouble(token.nextToken());
model = token.nextToken();
waterSupply = token.nextToken();
numberOfCups = Integer.parseInt(token.nextToken());
}
return new CoffeeBrewer(code, description, price, model, waterSupply, numberOfCups);
}
@Override
public Catalog loadCatalog(String filename) throws FileNotFoundException, IOException, DataFormatException {
Catalog catalog = new Catalog();
BufferedReader buffer = new BufferedReader(new FileReader(filename));
String line = buffer.readLine();
while (line != null) {
if (line.startsWith("Product")) {
catalog.addProduct(readProduct(line));
} else if(line.startsWith("Coffee")) {
catalog.addProduct(readCoffee(line));
} else if(line.startsWith("Brewer")) {
catalog.addProduct(readCoffeeBrewer(line));
}
line = buffer.readLine();
}
buffer.close();
return catalog;
}
}
TestFileCatalogLoader类
import java.io.*;
import java.util.*;
/**
* Tests the class <code>FileCatalogLoader</code>
*
* @author BlankSpace
* @version 1.0.0
* @see FileCatalogLoader
*/
public class TestFileCatalogLoader {
/* Standard output stream */
private static PrintWriter stdOut = new PrintWriter(System.out, true);
/* Standard error stream */
private static PrintWriter stdErr = new PrintWriter(System.err, true);
/**
* Tests methods of class {@link FileCatalogLoader}
*
* @param args not used.
* @throws IOException if an I/O error occurs.
*/
public static void main (String args[]) throws IOException {
stdOut.println("");
stdOut.println("Testing class FileCatalogLoader...");
TestFileCatalogLoader tester =
new TestFileCatalogLoader();
tester.testLoadCatalog();
stdOut.println("All tests passed");
stdOut.println("");
}
/**
* Displays a message in the standard error stream if the value specified
* by parameter <code>condition<code> is <code>false</code>.
*
* @param message the error message.
* @param condition the test condition.
* @return the value of <code>condition</code>
*/
public static void assertTrue(String message, boolean condition) {
if (!condition) {
stdErr.print("** Test failure ");
stdErr.println(message);
System.exit(1);
}
}
/**
* Displays a message in the standard error stream.
*
* @param message the error message.
* @return <code>false</code>;
*/
public static void fail(String message) {
stdErr.print("** Test failure ");
stdErr.println(message);
System.exit(1);
}
/**
* Tests the method <code>loadCatalog</code>.
*
* @return <code>true</code> if all test passed; otherwise returns
* <code>false</code>.
* @throws IOException if an I/O error occurs.
*/
public void testLoadCatalog() throws IOException {
CatalogLoader loader = new FileCatalogLoader();
try {
// Testing an empty file
Catalog emptyCatalog =
loader.loadCatalog("empty.dat");
assertTrue("1, testing method read with an empty file",
emptyCatalog instanceof Catalog);
assertTrue("2, testing method read with an empty file"
+ emptyCatalog.getNumberOfProducts() + " products loaded",
emptyCatalog.getNumberOfProducts() == 0);
// Testing a not empty file
Catalog catalog =
loader.loadCatalog("catalog.dat");
assertTrue("3, testing method loadCatalog",
catalog instanceof Catalog);
assertTrue("4, testing method loadCatalog: "
+ catalog.getNumberOfProducts() + " products loaded",
catalog.getNumberOfProducts() == 26);
// Testing product C001
Product product = catalog.getProduct("C001");
assertTrue("5, testing method loadCatalog" + product.toString(),
product instanceof Coffee);
Coffee coffeeC001 = (Coffee) product;
assertTrue("6, testing method loadCatalog: " +
coffeeC001.toString(),
coffeeC001.getCode().equals("C001") &&
coffeeC001.getDescription().equals("Colombia, Whole, 1 lb") &&
coffeeC001.getPrice() == 17.99 &&
coffeeC001.getOrigin().equals("Colombia") &&
coffeeC001.getRoast().equals("Medium") &&
coffeeC001.getFlavor().equals("Rich and Hearty") &&
coffeeC001.getAroma().equals("Rich") &&
coffeeC001.getAcidity().equals("Medium") &&
coffeeC001.getBody().equals("Full"));
// Testing product C002
product = catalog.getProduct("C002");
assertTrue("7, testing method loadCatalog: " + product.toString(),
product instanceof Coffee);
Coffee coffeeC002 = (Coffee) product;
assertTrue("8, testing method loadCatalog: " +
coffeeC002.toString(),
coffeeC002.getCode().equals("C002") &&
coffeeC002.getDescription().equals("Colombia, Ground, 1 lb") &&
coffeeC002.getPrice() == 18.75 &&
coffeeC002.getOrigin().equals("Colombia") &&
coffeeC002.getRoast().equals("Medium") &&
coffeeC002.getFlavor().equals("Rich and Hearty") &&
coffeeC002.getAroma().equals("Rich") &&
coffeeC002.getAcidity().equals("Medium") &&
coffeeC002.getBody().equals("Full"));
// Testing product A001
product = catalog.getProduct("A001");
assertTrue("9, testing method loadCatalog: " + product.toString(),
product instanceof Product);
assertTrue("10, testing method loadCatalog: " +
product.toString(),
product.getCode().equals("A001") &&
product.getDescription().equals("Almond Flavored Syrup") &&
product.getPrice() == 9.0);
// Testing product B002
product = catalog.getProduct("B002");
assertTrue("11, testing method loadCatalog: " + product.toString(),
product instanceof CoffeeBrewer);
CoffeeBrewer brewerB002 = (CoffeeBrewer) product;
assertTrue("12, testing method loadCatalog: " +
brewerB002.toString(),
brewerB002.getCode().equals("B002") &&
brewerB002.getDescription().equals("Coffee Brewer, 2 Warmers") &&
brewerB002.getPrice() == 200.0 &&
brewerB002.getModel().equals("Brewer 200") &&
brewerB002.getWaterSupply().equals("Pourover") &&
brewerB002.getNumberOfCups() == 12);
} catch (Exception e) {
fail("13, testing method loadCatalog: " + e.getMessage());
}
}
}
GourmetCoffeeSystem类
import java.io.*;
import java.util.*;
import java.text.*;
/**
* This class implements a gourmet coffee system.
*
* @author BlankSpace
* @version 1.1.0
* @see Product
* @see Coffee
* @see CoffeeBrewer
* @see Catalog
* @see OrderItem
* @see Order
* @see SalesFormatter
* @see PlainTextSalesFormatter
* @see HTMLSalesFormatter
* @see XMLSalesFormatter
* @see CatalogLoader
* @see FileCatalogLoader
*/
public class GourmetCoffee {
private static BufferedReader stdIn =
new BufferedReader(new InputStreamReader(System.in));
private static PrintWriter stdOut = new PrintWriter(System.out, true);
private static PrintWriter stdErr = new PrintWriter(System.err, true);
private Catalog catalog;
private Sales sales;
private SalesFormatter salesFormatter;
/**
* Loads catalog data from a file and starts the application.
* <p>
* The name of the file is specified in the command arguments.
* </p>
*
* @param args String arguments.
* @throws IOException if there are errors in the input.
*/
public static void main(String[] args) throws IOException {
Catalog catalog = null;
if (args.length != 1) {
stdErr.println("Usage: java GourmetCoffee filename");
} else {
try {
catalog =
(new FileCatalogLoader()).loadCatalog(args[0]);
} catch (FileNotFoundException fnfe) {
stdErr.println("The file does not exist");
System.exit(1);
} catch (DataFormatException dfe) {
stdErr.println("The file contains malformed data: "
+ dfe.getMessage());
System.exit(1);
}
GourmetCoffee application =
new GourmetCoffee(catalog);
application.run();
}
}
/**
* Constructs a <code>GourmetCoffee</code> object.
* Initializes the catalog data with the value specified
* in the parameter.
*
* @param initialCatalog a product catalog
*/
private GourmetCoffee(Catalog initialCatalog) {
this.catalog = initialCatalog;
this.sales = new Sales();
this.salesFormatter =
PlainTextSalesFormatter.getSingletonInstance();
loadSales();
}
/**
* Initializes the sales object.
*/
private void loadSales() {
Order orderOne = new Order();
Product productOne = this.catalog.getProduct("C001");
if (productOne != null) {
orderOne.addItem(new OrderItem(productOne, 5));
this.sales.addOrder(orderOne);
}
Order orderTwo = new Order();
Product productTwo = this.catalog.getProduct("C002");
Product productThree = this.catalog.getProduct("A001");
if ((productTwo != null) && (productThree != null)) {
orderTwo.addItem(new OrderItem(productTwo, 2));
orderTwo.addItem(new OrderItem(productThree, 2));
this.sales.addOrder(orderTwo);
}
Order orderThree = new Order();
Product productFour = this.catalog.getProduct("B002");
if (productFour != null) {
orderThree.addItem(new OrderItem(productFour, 1));
this.sales.addOrder(orderThree);
}
}
/**
* Presents the user with a menu of options and executes the
* selected task.
*/
private void run() throws IOException {
int choice = getChoice();
while (choice != 0) {
if (choice == 1) {
displayCatalog();
} else if (choice == 2) {
this.salesFormatter =
PlainTextSalesFormatter.getSingletonInstance();
writeFile(
readFilename(),
this.salesFormatter.formatSales(this.sales));
} else if (choice == 3) {
this.salesFormatter =
HTMLSalesFormatter.getSingletonInstance();
writeFile(
readFilename(),
this.salesFormatter.formatSales(this.sales));
} else if (choice == 4) {
this.salesFormatter =
XMLSalesFormatter.getSingletonInstance();
writeFile(
readFilename(),
this.salesFormatter.formatSales(this.sales));
}
choice = getChoice();
}
}
/**
* Displays a menu of options and verifies the user's choice.
*
* @return an integer in the range [0,7]
*/
private int getChoice() throws IOException {
int input;
do {
try {
stdErr.println();
stdErr.print("[0] Quit\n"
+ "[1] Display Catalog\n"
+ "[2] Save sales (Plain Text)\n"
+ "[3] Save sales (HTML)\n"
+ "[4] Save sales (XML)\n"
+ "choice> ");
stdErr.flush();
input = Integer.parseInt(stdIn.readLine());
stdErr.println();
if (0 <= input && 4 >= input) {
break;
} else {
stdErr.println("Invalid choice: " + input);
}
} catch (NumberFormatException nfe) {
stdErr.println(nfe);
}
} while (true);
return input;
}
/**
* Displays the catalog.
*/
private void displayCatalog() {
int size = this.catalog.getNumberOfProducts();
if (size == 0) {
stdErr.println("The catalog is empty");
} else {
for (Product product : this.catalog) {
stdOut.println(product.getCode() + " "
+ product.getDescription());
}
}
}
/**
* Creates a new file (which has the specified name) and writes
* the specified string to the new file.
*
* @param filename name of the file that will store the data
* @param content data to be stored
*/
private void writeFile(String filename, String content)
throws IOException {
/* PLACE YOUR CODE HERE */
BufferedWriter buffer = new BufferedWriter(new FileWriter(filename));
buffer.write(content);
buffer.close();
}
/**
* Prompts the user for a filename (the name of the file that
* will store the sales information) and returns the user's
* response.
*
* @return name of a file
*/
private String readFilename() throws IOException {
stdErr.print("Filename> ");
stdErr.flush();
return stdIn.readLine();
}
}