作者:A.y.
日期:2019/5/12
上机环境:eclipse
第四章作业
一、题目要求
同学们应该都去麦当劳或肯德基吃过快餐吧?请同学们参考肯德基官网的信息模拟肯德基快餐店的收银系统,合理使用C++或Java或Python结合设计模式(2种以上)至少实现系统的以下功能:
1.正常餐品结算和找零。
2.基本套餐结算和找零。
3.使用优惠劵购买餐品结算和找零。
4.可在一定时间段参与店内活动(自行设计或参考官网信息)。
5.模拟打印小票的功能(写到文件中)。
二、基本思路分析
利用工厂方法模式用于产生每一种顾客点的产品,每个产品有一个价格属性和一个返回价格的函数,每一种产品对应一种工厂类,每个产品工厂类中的实现接口Factory(),并实现方法Method()用于生产每一种产品对象。在客户类中,使用单例模式创建唯一的客户对象,Menu()方法用来显示点餐界面,Choice()方法用来接收顾客单次点餐信息,并调用Ininform()函数记录相应的点餐信息,ShowMessage()函数用来显示顾客已点餐的信息,disCount()函数用来计算顾客优惠卷以及活动后的折扣价,Intext()函数用来将顾客的点餐信息存入文件中(模拟小票打印功能),InDatabase()函数用来将顾客点餐餐品的详细信息及价格存入数据库中记录。
三、UML类图
工厂方法模式(餐品以及餐品工厂类):
单例模式(客户类):
四、主要运行代码
package kfc收银系统;
import java.util.Scanner;
import java.util.Date;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
public class Client {
private static Client instance = null;
String[] name = new String[9]; //表示用户已点餐品名
int[] num = new int[9]; //表示已点餐品对应分份数
int choice,number; //餐品编号以及餐品份数
int money,change; //顾客支付收款、找零数
static int price=0,symbol=0,i=0; //餐品总额和顾客点完餐标志
public static Client getClient() {
if(instance==null)
{
instance = new Client();
}
return instance;
}
public static void menu() { //主菜单函数
System.out.println("\t\t欢迎来到KFC,请点餐 (在每月的8,18,28号有八折活动(不能与会员卡同时使用))\n");
System.out.println("\t\t1.鸡腿:10元/个 \t2.汉堡:14元/个");
System.out.println("\t\t3.鸡肉卷:12元/个\t4.黄金鸡块:8元/份");
System.out.println("\t\t5.蛋挞:4元/个 \t6.薯条:8元/份");
System.out.println("\t\t7.牛角五方:7元/个");
System.out.println("\t\t8.果汁:6元/杯 \t9.可乐:6元/杯");
System.out.println("\t\t10.单人套餐1:鸡腿一个+鸡肉卷一个+可乐一杯 24元/份");
System.out.println("\t\t11.单人套餐2:汉堡一个+薯条一份+果汁一杯 23元/份");
System.out.println("\t\t12.双人套餐1:鸡腿一个+汉堡一个+蛋挞两个+黄金鸡块一份+可乐两杯 44元/份");
System.out.println("\t\t13.双人套餐2:汉堡一个+鸡肉卷一个+牛角五方两个+薯条一份+果汁两杯 49元/份");
System.out.println("\t\t14.结束点餐");
}
public void Number(String nam) { //顾客点餐份数函数
System.out.print("\t请输入所需餐品("+nam+")份数:");
Scanner sc1 = new Scanner(System.in);
number = sc1.nextInt();
}
public void Ininform(int a,String b) { //记录顾客点餐和餐品份数函数
int symbol=0,j;
for(j=0;j<=i;j++)
if(b.equals(name[j]))
{
symbol=1;
break;
}
if(symbol==0)
{
name[i]=b;
num[i]=a;
i++;
}
else
num[j]=num[j]+a;
}
public void showMessage() { //显示顾客点餐信息函数
System.out.println("已点餐:"+i);
for(int j=0;j<i;j++)
System.out.println("\t"+name[j]+"×"+num[j]);
}
public void Intext() { //模拟打印小票函数
Date d = new Date();
DateFormat me =DateFormat.getDateTimeInstance(DateFormat.MEDIUM,DateFormat.MEDIUM);
try {
File fp=new File("ticket.txt");
fp.createNewFile();
try(FileWriter writer=new FileWriter(fp);
BufferedWriter out=new BufferedWriter(writer)
){
out.write("消费小票:");
out.newLine();
out.write(" 点餐信息:");
out.newLine();
for(int j=0;j<i;j++)
{
out.write(" "+name[j]+"×"+num[j]);
}
out.newLine();
out.write(" 消费总价:"+price);
out.newLine();
out.write(" 消费时间:"+me.format(d));
}
}catch(IOException e) {
e.printStackTrace();
}
}
public void Choice() { //顾客单次选餐函数
int a=0,n=0; //a表示点餐价格,n表示点餐餐品类数
String nam=null; //nam表示点餐名
Scanner sc2 = new Scanner(System.in);
System.out.print("\n\t请输入点餐号:");
choice = sc2.nextInt();
switch(choice) {
case 1:
nam="鸡腿";
n=1;
a=new DrumstickFactory().Method().setPrice();
break;
case 2:
nam="汉堡";
n=1;
a=new HamburgerFactory().Method().setPrice();
break;
case 3:
nam="鸡肉卷";
n=1;
a=new ChickenRollsFactory().Method().setPrice();
break;
case 4:
nam="黄金鸡块";
n=1;
a=new ChickenNuggetsFactory().Method().setPrice();
break;
case 5:
nam="蛋挞";
n=1;
a=new EggTartFactory().Method().setPrice();
break;
case 6:
nam="薯条";
n=1;
a=new ChipsFactory().Method().setPrice();
break;
case 7:
nam="牛角五方";
n=1;
a=new CroissantFactory().Method().setPrice();
break;
case 8:
nam="果汁";
n=1;
a=new JuiceFactory().Method().setPrice();
break;
case 9:
nam="可乐";
n=1;
a=new ColoFactory().Method().setPrice();
break;
case 10:
nam="单人套餐1";
Number(nam);
Ininform(number,"鸡腿");
Ininform(number,"鸡肉卷");
Ininform(number,"可乐");
a=new Combo1Factory().getPrice();
break;
case 11:
nam="单人套餐2";
Number(nam);
Ininform(number,"汉堡");
Ininform(number,"薯条");
Ininform(number,"果汁");
a=new Combo2Factory().getPrice();
break;
case 12:
nam="双人套餐1";
Number(nam);
Ininform(number,"汉堡");
Ininform(number,"鸡腿");
Ininform(number*2,"可乐");
Ininform(number*2,"蛋挞");
Ininform(number,"黄金鸡块");
a=new Combo3Factory().getPrice();
break;
case 13:
nam="双人套餐2";
Number(nam);
Ininform(number,"汉堡");
Ininform(number,"鸡肉卷");
Ininform(number*2,"果汁");
Ininform(number*2,"牛角五方");
Ininform(number,"薯条");
a=new Combo4Factory().getPrice();
break;
case 14:
symbol=1;
return;
}
if(choice<10)
{
Number(nam);
Ininform(number,nam);
}
price=price+a*number;
}
public void order() { //顾客点餐函数
int i=0;
menu();
while(symbol==0)
{
Choice();
showMessage();
}
}
public int Change(int n) { //顾客找零函数
change=n-price;
return change;
}
public void discount() { //顾客打折函数
Calendar now = Calendar.getInstance();
int a =now.get(Calendar.DAY_OF_MONTH);
if(a==8||a==18||a==28)
{
System.out.println("\n\t今天是优惠日!可享受八折折扣!");
price=(int)(price*0.8);
}
else
{
String m;
Scanner sc4 = new Scanner(System.in);
System.out.print("\n\t今天不是优惠日...是否有优惠券(优惠券打8.8折):");
m = sc4.next();
if(m.equals("是"))
price=(int)(price*0.88);
}
}
public void InDatabase() throws ClassNotFoundException, SQLException{ //数据库记录函数
String driverName="com.microsoft.sqlserver.jdbc.SQLServerDriver";
String dbURL="jdbc:sqlserver://127.0.0.1:1433;DatabaseName=KFC";//kfc为我的数据库名
String userName="sa";//我的数据库用户名
String userPwd="a291374161";//我的密码
int s=1;
Class.forName(driverName);
try{
Connection con=DriverManager.getConnection(dbURL,userName,userPwd);
Statement stmt1 = con.createStatement();
Statement stmt2 = con.createStatement();
Statement stmt3 = con.createStatement();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date date = new Date();
ResultSet rs1 = stmt1.executeQuery("SELECT * FROM kfc"); //查询数据库内数据
String o = dateFormat.format(date); //o为当前日期的标准模式
if(rs1.next()) //初始化当天的销售记录
{
while(!o.equals(rs1.getString("日期")))
{
if(!rs1.next())
{
s=0;
break;
}
}
if(s==0)
{
String A = "INSERT INTO kfc VALUES('"+o+"','0','0','0','0','0','0','0','0','0','0')";
stmt1.executeUpdate(A);
}
}
else
{
String A = "INSERT INTO kfc VALUES('"+o+"','0','0','0','0','0','0','0','0','0','0')";
stmt1.executeUpdate(A);
}
ResultSet rs2 = stmt2.executeQuery("SELECT * FROM kfc");
while(rs2.next())
if(rs2.getString("日期").equals(o))
{
break;
}
String B = "UPDATE kfc SET 销售额 ="+price+"+"+rs2.getInt("销售额")+" WHERE 日期='"+o+"'";
stmt2.executeUpdate(B); //更新当天的销售额
for(int j=0;j<i;j++)
{
ResultSet rs3 = stmt3.executeQuery("SELECT * FROM kfc");
while(rs3.next())
if(rs3.getString("日期").equals(o))
{
break;
}
int p=num[j]+rs3.getInt(name[j]);
String C = "UPDATE kfc SET "+name[j]+" = "+p+" WHERE 日期='"+o+"'";
stmt3.executeUpdate(C); //更新当天的销售量
}
}catch(SQLException e)
{
e.printStackTrace();
System.out.print("数据库连接失败!");
}
}
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Client c = getClient();
Scanner sc3 = new Scanner(System.in);
c.order(); //顾客点餐
c.discount(); //顾客是否享受折扣
System.out.print(" 点餐价格:"+price);
System.out.print("\t实际收款:");
c.money = sc3.nextInt(); //输入收到顾客的钱
System.out.println("\n 找零:"+c.Change(c.money)); //返回找零数
c.Intext(); //模拟开小票功能
c.InDatabase(); //销售信息存入数据库
}
}
五、调试截图
1.点同样的餐品时点餐信息会重复出现
错误代码
错误原因是未加入点餐重复判断代码
修改后:
2.初始化数据库信息时,无法插入java中自己定义的变量(o是定义的字符串变量)
错误代码:
错误原因:插入变量形式错误,应该是要用”+变量名+”的形式与sql语句连接。
修改后:
3.数据库查询问题,要匹配插入的数据信息是否为当天的数据信息时,发现无法查询当前行的信息。
错误代码
错误原因是由于调用executeQuery()方法查询时,返回的查询结果指针指向的是第一条记录的上一条记录,但实际上并不存在这一条记录,因此需要调用ResultSet类中的next()方法来指向记录的第一行才可以查询记录。
修改后:
3.初始化第二天点餐信息出现插入错误
错误代码:
错误原因是由于在这段代码内只判断了数据库内是否为空行以及第一行的日期属性是否与当前日期一致,若不一致则插入当天的初始化销售数据,没有考虑到数据库可能会有多行数据,应该让每一行的日期属性都与当天日期比较,都不一致再插入当天的初始化销售数据
修改后:
六、运行截图
控制台点餐:
数据库记录:
模拟小票:
个人总结:
在这次的章节作业中用到了很多之前没有试过的东西,之前的写代码的时候大部分类都冗余在一个主类中,上一次作业接触了简单的几种设计模式之后,对于代码设计的清晰性更加的了解了。在这次设计中我用到了连接数据库的方法,在调试的时候遇到了很多的问题,ResultSet中的next()函数是将数据库指针指向下一行,若下一行不存在则返回值为false,否则为true,但是在设计的时候我的思路是想先判断下一行是否存在再决定是否指向下一行的,需要添加标记变量才能做到;还遇到一个比较棘手的问题就是”结果集已关闭”,这个问题主要是因为ResultSet内嵌套使用ResultSet引起的,在java里每个ResultSet结果集都需要一个单独的Statement来支撑,如果想使用多个Result就必须使用创建多个Statement,因为我将消费记录的初始化、销售额的累加以及餐品销量的累加分别创建了3个Statement对象来进行存储,在这次作业之后我也对java连接数据库的操作第一次有了这么多的了解。
个人博客: