blog--2

发布时间 2023-11-19 09:59:57作者: 跃动核子

一、前言:

在本次博客中,我们将探讨PTA第4、5、6次大作业和期中考试涉及的知识点。主要内容包括理解类的概念,创建类和实例化对象,定义方法,方法的参数传递和返回值,以及使用条件语句(if-else)、循环语句(for、while)等来控制菜单存储和用户输入。

在第四题的菜单题中,我们将重点关注基本的菜单显示和用户输入处理,而在第五和第六题中,我们需要考虑异常输入的处理,并且利用更复杂的数据结构来实现菜单功能。这些题目的难度各不相同,其中第四题相对较为简单,而第五和第六题则需要对类的设计和方法实现进行深入的思考。

本次考试的题量适中,第四题可能相对简单,而第五和第六题则侧重于对类的设计和方法实现的考察。除此之外,还会涉及到遍历排序和日期比较等基础知识和库函数知识。

总的来说,第五和第六道题目将大幅增加复杂度,减少题目数量,其编程设计需要考虑更多的设计和实现细节。通过本次博客,我们将深入研究这些知识点,并讨论如何解决相关的编程问题。希望本次博客能够帮助大家更好地理解和掌握这些关键的编程概念。

二、设计与分析:

(1)第一次题目集

本次题目集难度适中,我们着重分析两道菜单题目:

7-1

7-1 菜单计价程序-3

分数 40

全屏浏览题目

切换布局

作者 蔡轲

单位 南昌航空大学

设计点菜计价程序,根据输入的信息,计算并输出总价格。

输入内容按先后顺序包括两部分:菜单、订单,最后以"end"结束。

菜单由一条或多条菜品记录组成,每条记录一行

每条菜品记录包含:菜名、基础价格 两个信息。

订单分:桌号标识、点菜记录和删除信息、代点菜信息。每一类信息都可包含一条或多条记录,每条记录一行或多行。

桌号标识独占一行,包含两个信息:桌号、时间。

桌号以下的所有记录都是本桌的记录,直至下一个桌号标识。

点菜记录包含:序号、菜名、份额、份数。份额可选项包括:1、2、3,分别代表小、中、大份。

不同份额菜价的计算方法:小份菜的价格=菜品的基础价格。中份菜的价格=菜品的基础价格1.5。小份菜的价格=菜品的基础价格2。如果计算出现小数,按四舍五入的规则进行处理。

删除记录格式:序号 delete

标识删除对应序号的那条点菜记录。

如果序号不对,输出"delete error"

代点菜信息包含:桌号 序号 菜品名称 份额 分数

代点菜是当前桌为另外一桌点菜,信息中的桌号是另一桌的桌号,带点菜的价格计算在当前这一桌。

程序最后按输入的先后顺序依次输出每一桌的总价(注意:由于有代点菜的功能,总价不一定等于当前桌上的菜的价格之和)。

每桌的总价等于那一桌所有菜的价格之和乘以折扣。如存在小数,按四舍五入规则计算,保留整数。

折扣的计算方法(注:以下时间段均按闭区间计算):

周一至周五营业时间与折扣:晚上(17:00-20:30)8折,周一至周五中午(10:30--14:30)6折,其余时间不营业。

周末全价,营业时间:9:30-21:30

如果下单时间不在营业范围内,输出"table " + t.tableNum + " out of opening hours"

参考以下类的模板进行设计:菜品类:对应菜谱上一道菜的信息。

Dish {

String name;//菜品名称

int unit_price; //单价

int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) }

菜谱类:对应菜谱,包含饭店提供的所有菜的信息。

Menu {

Dish\[\] dishs ;//菜品数组,保存所有菜品信息

Dish searthDish(String dishName)//根据菜名在菜谱中查找菜品信息,返回Dish对象。

Dish addDish(String dishName,int unit_price)//添加一道菜品信息

}

点菜记录类:保存订单上的一道菜品记录

Record {

int orderNum;//序号\\

Dish d;//菜品\\

int portion;//份额(1/2/3代表小/中/大份)\\

int getPrice()//计价,计算本条记录的价格\\

}

订单类:保存用户点的所有菜的信息。

Order {

Record\[\] records;//保存订单上每一道的记录

int getTotalPrice()//计算订单的总价

Record addARecord(int orderNum,String dishName,int portion,int num)//添加一条菜品信息到订单中。

delARecordByOrderNum(int orderNum)//根据序号删除一条记录

findRecordByNum(int orderNum)//根据序号查找一条记录

}

### 输入格式:

桌号标识格式:table + 序号 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 时间(24小时制格式: HH/MM/SS)

菜品记录格式:

菜名+英文空格+基础价格

如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。

点菜记录格式:序号+英文空格+菜名+英文空格+份额+英文空格+份数注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。

删除记录格式:序号 +英文空格+delete

代点菜信息包含:桌号+英文空格+序号+英文空格+菜品名称+英文空格+份额+英文空格+分数

最后一条记录以“end”结束。

### 输出格式:

按输入顺序输出每一桌的订单记录处理信息,包括:

1、桌号,格式:table+英文空格+桌号+”:”

2、按顺序输出当前这一桌每条订单记录的处理信息,

每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品\*份数,序号是之前输入的订单记录的序号。如果订单中包含不能识别的菜名,则输出“\*\* does not exist”,\*\*是不能识别的菜名

如果删除记录的序号不存在,则输出“delete error”

最后按输入顺序一次输出每一桌所有菜品的总价(整数数值)格式:table+英文空格+桌号+“:”+英文空格+当前桌的总价

本次题目不考虑其他错误情况,如:桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等,在本系列的后续作业中会做要求。

输入格式:

桌号标识格式:table + 序号 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 时间(24小时制格式: HH/MM/SS)

菜品记录格式:

菜名+英文空格+基础价格

如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。

点菜记录格式:序号+英文空格+菜名+英文空格+份额+英文空格+份数注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。

删除记录格式:序号 +英文空格+delete

代点菜信息包含:桌号+英文空格+序号+英文空格+菜品名称+英文空格+份额+英文空格+分数

最后一条记录以“end”结束。

输出格式:

按输入顺序输出每一桌的订单记录处理信息,包括:

1、桌号,格式:table+英文空格+桌号+“:”+英文空格

2、按顺序输出当前这一桌每条订单记录的处理信息,

每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品\*份数,序号是之前输入的订单记录的序号。如果订单中包含不能识别的菜名,则输出“\*\* does not exist”,\*\*是不能识别的菜名

如果删除记录的序号不存在,则输出“delete error”

最后按输入顺序一次输出每一桌所有菜品的总价(整数数值)格式:table+英文空格+桌号+“:”+英文空格+当前桌的总价

本次题目不考虑其他错误情况,如:桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等,在本系列的后续作业中会做要求。

以上代码是一个简单的餐厅点餐系统的实现,其中包括菜单管理、订单记录、时间判断等功能。下面是对代码的简要分析:

Dish类:

用于表示菜品,包括菜名和单价。

提供根据份量计算价格的方法。

Menu类:

用于管理菜单,包括添加菜品和查询菜品信息。

Record类:

用于表示订单中的记录,包括订单号、菜品、份量、数量等信息。

能够标记记录是否被删除,并计算记录的价格。

Order类:

用于管理订单,包括添加记录、删除记录、获取总价格等功能。

记录了当前桌号和日期信息。

Main类:

包含主程序入口,实现了交互式的点餐系统逻辑。

通过输入指令来添加菜品、增加订单、删除订单等操作。

时间判断方法:

使用Calendar类获取当前时间的星期和具体时间信息,并结合预先设定的营业时间和折扣规则,判断当前时间段是否在营业时间内,以及是否有折扣。

主程序逻辑:

在主函数中,通过循环读取用户输入的指令来进行菜单管理和订单管理,并根据输入执行相应的操作。

这段代码实现了一个简单的餐厅点餐系统,包括基本的菜单管理和订单管理功能,以及针对时间的营业时间判断,但由于时间安排问题,本代码并未完全完成,以下是该题代码的复杂度分析以及类图:

代码如下:

import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.Calendar;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.text.DecimalFormat;

class Dish {
private String name;
protected int unit_price;

public Dish(String name, int unit_price) {
this.name = name;
this.unit_price = unit_price;
}

public int getPrice(int portion) {
float b[] = {1, 1.5f, 2};
return Math.round(unit_price * b[portion-1]);
}

public String getName() {
return name;
}
}

class Menu {
private Map<String, Dish> menuMap;

public Menu() {
menuMap = new HashMap<>();
}

public void addDish(String dishName, int unit_price){
if(menuMap.containsKey(dishName)) {
Dish dish = menuMap.get(dishName);
dish.unit_price = unit_price;
} else {
Dish dish = new Dish(dishName, unit_price);
menuMap.put(dishName, dish);
}
}

public Dish searchDish(String dishName) {
return menuMap.getOrDefault(dishName, null);
}
}


class Record {
public int orderNum;
private Dish dish;
private int portion;
private int num;
private boolean isDeleted; // 是否被删除

public Record(int orderNum, Dish dish, int portion, int num) {
this.orderNum = orderNum;
this.dish = dish;
this.portion = portion;
this.num = num;
this.isDeleted = false;
}

public boolean isDeleted() {
return isDeleted;
}

public void markAsDeleted() {
this.isDeleted = true;
}

public int getPrice() {
if (dish != null) {
return dish.getPrice(portion) * num;
} else {
return 0;
}
}

public String getRecordString() {
int price = getPrice();
if (price == 0) {
return orderNum + " " + dish.getName() + " does not exist";
} else {
return orderNum + " " + dish.getName() + " " + price;
}
}

public int getOrderNum() {
return orderNum;
}

public Dish getDish() {
return dish;
}
}

class Order {
private Map<Integer, Record[]> tableRecordsMap;
private static int tableCount = 1;
public int currentTable;
private LocalDate date;

public Order() {//LocalDate date
tableRecordsMap = new HashMap<>();
currentTable = tableCount;
tableCount++;
this.date = date;
}

public String getTableString() { // 获取桌号字符串
return "table " + currentTable + ": ";
}



public void printAllRecordStringWithoutTableString() {
if (tableRecordsMap.containsKey(currentTable)) {
Record[] records = tableRecordsMap.get(currentTable);
if(records.length > 0) {
System.out.println(getTableString());
for (Record record : records) {
if (record != null) {
if (record.isDeleted()) {
System.out.println(record.getRecordString());
} else {
System.out.println(record.getRecordString());
}
}
}
}
}
}

public int getTotalPrice() {
int totalPrice = 0;
if (tableRecordsMap.containsKey(currentTable)) {
Record[] records = tableRecordsMap.get(currentTable);
for (Record record : records) {
if (record != null && !record.isDeleted()) {
totalPrice += record.getPrice();
}
}
}
return totalPrice;
}

public void addARecord(int orderNum, String dishName, int portion, int num, Menu menu) {
Dish dish = menu.searchDish(dishName);
if (dish == null) {
System.out.println(getTableString() + dishName + " does not exist");
} else {
if (!tableRecordsMap.containsKey(currentTable)) {
tableRecordsMap.put(currentTable, new Record[0]);
}
Record[] records = tableRecordsMap.get(currentTable);
Record record = new Record(orderNum, dish, portion, num);
Record[] newRecords = new Record[records.length + 1];
System.arraycopy(records, 0, newRecords, 0, records.length);
newRecords[newRecords.length - 1] = record;
tableRecordsMap.put(currentTable, newRecords);

}
}

public void delARecordByOrderNum(int orderNum) {
if (tableRecordsMap.containsKey(currentTable)) {
Record[] records = tableRecordsMap.get(currentTable);
int index = -1;
for (int i = 0; i < records.length; i++) {
if (records[i] != null && records[i].orderNum == orderNum) {
index = i;
break;
}
}
if (index == -1) {
System.out.println(getTableString() + "delete error");
return;
}
Record record = records[index];
if (record != null) {
record.markAsDeleted();
}
} else {
System.out.println(getTableString() + "delete error");
}
}

public LocalDate getDate() {




return date;
}



public static double judgetime(int[] time)
{
/*周一至周五营业时间与折扣:晚上(17:00-20:30)8折,周一至周五中午(10:30--14:30)6折,其余时间不营业。
周末全价,营业时间:9:30-21:30*/
double n=0;
double temp=0;
Calendar calendar = Calendar.getInstance();
calendar.set(time[1],(time[2]-1),time[3]);
int weekday = calendar.get(Calendar.DAY_OF_WEEK);
//获取星期几,周日为1,周一为2
n=time[4]*3600+time[5]*60+time[6];
//17:00-20:30 61200-73800
//10:30-14:30 37800-52200

if(weekday>1&&weekday<7)
{
if (n>=37800&&n<=52200)
{
temp=0.6;
}
else if(n>=61200&&n<=73800)
{
temp=0.8;
}
else
{
temp=0;
}
}
//9:30-21:30 34200-77400
else if(weekday==1||weekday==7)
{
if (n>=34200&&n<=77400)
{
temp=1;
}
else
{
temp=0;
}
}
// System.out.print(weekday+" "+n+" "+temp+"\n");
return temp;
}
public static boolean isTimeInRange(LocalDateTime time, LocalTime startTime, LocalTime endTime) {
LocalTime givenTime = time.toLocalTime();
return givenTime.isAfter(startTime) && givenTime.isBefore(endTime);
}
}



public class Main {
public static void main(String[] args) {
Order order = null;
Scanner sc = new Scanner(System.in);
Menu menu = new Menu();
int[] time=new int[7];
while (true) {
String inputLine = sc.nextLine();

if (inputLine.equals("end")) {
break;
}

String[] inputs = inputLine.split(" ");

if (inputs[0].startsWith("table")) {
if (order != null) {
order.printAllRecordStringWithoutTableString();
System.out.println(order.getTableString() + order.getTotalPrice());
}
String[] dateParts = inputs[2].split("/");

time[1]= Integer.parseInt(dateParts[0]);
time[2] = Integer.parseInt(dateParts[1]);
time[3] = Integer.parseInt(dateParts[2]);

String[] dateParts2 = inputs[3].split("/");
time[4]= Integer.parseInt(dateParts2[0]);
time[5] = Integer.parseInt(dateParts2[1]);
time[6] = Integer.parseInt(dateParts2[2]);


} else if (!inputs[0].matches("\\d+")) {
String dishName = inputs[0];
int unitPrice = Integer.parseInt(inputs[1]);
menu.addDish(dishName, unitPrice);
} else if (inputs[1].equals("delete")) {
int orderNum = Integer.parseInt(inputs[0]);
order.delARecordByOrderNum(orderNum);
} else {
int orderNum = Integer.parseInt(inputs[0]);
String dishName = inputs[1];
int portion = Integer.parseInt(inputs[2]);
int num=Integer.parseInt(inputs[3]);

if (order==null){order=new Order();}
order.addARecord(orderNum, dishName, portion, num, menu);
}
}
if (order != null) {
order.printAllRecordStringWithoutTableString();
if(Order.judgetime(time)!=0)
{System.out.println(order.getTableString() + Math.round(order.getTotalPrice()*Order.judgetime(time)));}
else if(Order.judgetime(time)==0)
System.out.print("table "+order.currentTable+ " out of opening hours");

}
}
}

7-4

7-4 菜单计价程序-2

分数 40

全屏浏览题目

切换布局

作者 蔡轲

单位 南昌航空大学

设计点菜计价程序,根据输入的信息,计算并输出总价格。

输入内容按先后顺序包括两部分:菜单、订单,最后以"end"结束。

菜单由一条或多条菜品记录组成,每条记录一行

每条菜品记录包含:菜名、基础价格 两个信息。


订单分:点菜记录和删除信息。每一类信息都可包含一条或多条记录,每条记录一行。
点菜记录包含:序号、菜名、份额、份数。
份额可选项包括:1、2、3,分别代表小、中、大份。

删除记录格式:序号 delete

标识删除对应序号的那条点菜记录。

不同份额菜价的计算方法:
小份菜的价格=菜品的基础价格。
中份菜的价格=菜品的基础价格1.5。
小份菜的价格=菜品的基础价格
2。
如果计算出现小数,按四舍五入的规则进行处理。

参考以下类的模板进行设计:
菜品类:对应菜谱上一道菜的信息。

Dish {

String name;//菜品名称

int unit_price; //单价

int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) }

菜谱类:对应菜谱,包含饭店提供的所有菜的信息。

Menu {

Dish[] dishs ;//菜品数组,保存所有菜品信息

Dish searthDish(String dishName)//根据菜名在菜谱中查找菜品信息,返回Dish对象。

Dish addDish(String dishName,int unit_price)//添加一道菜品信息

}

点菜记录类:保存订单上的一道菜品记录

Record {

int orderNum;//序号\

Dish d;//菜品\

int portion;//份额(1/2/3代表小/中/大份)\

int getPrice()//计价,计算本条记录的价格\

}

订单类:保存用户点的所有菜的信息。

Order {

Record[] records;//保存订单上每一道的记录

int getTotalPrice()//计算订单的总价

Record addARecord(int orderNum,String dishName,int portion,int num)//添加一条菜品信息到订单中。

delARecordByOrderNum(int orderNum)//根据序号删除一条记录

findRecordByNum(int orderNum)//根据序号查找一条记录

}

输入格式:

菜品记录格式:

菜名+英文空格+基础价格

如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。

点菜记录格式:
序号+英文空格+菜名+英文空格+份额+英文空格+份数
注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。

删除记录格式:序号 +英文空格+delete


最后一条记录以“end”结束。

输出格式:

按顺序输出每条订单记录的处理信息,

每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品*份数,序号是之前输入的订单记录的序号。
如果订单中包含不能识别的菜名,则输出“** does not exist”,**是不能识别的菜名

如果删除记录的序号不存在,则输出“delete error”

最后输出订单上所有菜品的总价(整数数值),

本次题目不考虑其他错误情况,如:菜单订单顺序颠倒、不符合格式的输入、序号重复等。

该题目相较于菜单三难度降低很多,代码及分析如下:

import java.util.Scanner;

class Dish {
private String name;
protected int unit_price;

public Dish(String name, int unit_price) {
this.name = name;
this.unit_price = unit_price;
}

public int getPrice(int portion) {
float b[] = {1, 1.5f, 2};
return Math.round(unit_price * b[portion-1]);
}

public String getName() {
return name;
}
}

class Menu {
private Dish[] dishes;

public Menu() {
dishes = new Dish[0];
}

public void addDish(String dishName, int unit_price){
for (Dish dish : dishes) {
if (dish.getName().equals(dishName)) {
dish.unit_price = unit_price;
return;
}
}
Dish[] newDishes = new Dish[dishes.length+1];
System.arraycopy(dishes, 0, newDishes, 0, dishes.length);
newDishes[newDishes.length-1] = new Dish(dishName, unit_price);
dishes = newDishes;
}

public Dish searchDish(String dishName) {
for (Dish dish : dishes) {
if (dish.getName().equals(dishName)) {
return dish;
}
}
return null;
}
}

class Record {
public int orderNum;
private Dish dish;
private int portion;
private int num;

public Record(int orderNum, Dish dish, int portion, int num) {
this.orderNum = orderNum;
this.dish = dish;
this.portion = portion;
this.num = num;
}

public int getPrice() {
if (dish != null) {
return dish.getPrice(portion) * num;
} else {
return 0;
}
}

public String getRecordString() {
int price = getPrice();
if (price == 0) {
return orderNum + " " + dish.getName() + " does not exist";
} else {
return orderNum + " " + dish.getName() + " " + price;
}
}
}

class Order {
private Record[] records;

public Order() {
records = new Record[0];
}

public int getTotalPrice() {
int totalPrice = 0;
for (Record record : records) {
if (record != null) {
totalPrice += record.getPrice();
}
}
return totalPrice;
}

public Record addARecord(int orderNum, String dishName, int portion, int num, Menu menu) {
Dish dish = menu.searchDish(dishName);
if (dish == null) {
System.out.println(dishName + " does not exist");
return null;
}

Record record = new Record(orderNum, dish, portion, num);

Record[] newRecords = new Record[records.length+1];
System.arraycopy(records, 0, newRecords, 0, records.length);
newRecords[newRecords.length-1] = record;
records = newRecords;

return record;
}


public void delARecordByOrderNum(int orderNum) {
int index = -1;
for (int i = 0; i < records.length; i++) {
if (records[i] != null && records[i].orderNum == orderNum) {
index = i;
break;
}
}
if (index == -1) {
System.out.println("delete error;");
return;
}
Record[] newRecords = new Record[records.length-1];
System.arraycopy(records, 0, newRecords, 0, index);
System.arraycopy(records, index+1, newRecords, index, records.length-index-1);
records = newRecords;
}

public Record findRecordByNum(int orderNum) {
for (Record record : records) {
if (record != null && record.orderNum == orderNum) {
return record;
}
}
return null;
}
}

public class Main {
public static void main(String[] args) {
Order order = new Order();
Scanner sc = new Scanner(System.in);
Menu menu = new Menu(); // 实例化Menu对象

while (true) {
String inputLine = sc.nextLine();

if (inputLine.equals("end")) {
break;
}

String[] inputs = inputLine.split(" ");

if (!inputs[0].matches("\\d+")) {
String dishName = inputs[0];
int unitPrice = Integer.parseInt(inputs[1]);
menu.addDish(dishName, unitPrice);
} else if (inputs[1].equals("delete")) {
int orderNum = Integer.parseInt(inputs[0]);
//添加错误删除信息判断
order.delARecordByOrderNum(orderNum);
} else {
int orderNum = Integer.parseInt(inputs[0]);
String dishName = inputs[1];
int portion = Integer.parseInt(inputs[2]);
int num = Integer.parseInt(inputs[3]);

Record record = order.addARecord(orderNum, dishName, portion, num, menu); // 将menu作为参数传入
if (record != null) {
System.out.println(record.getRecordString());
}

}
}

System.out.println(order.getTotalPrice());
}
}

以上代码是一个简单的订单管理系统,主要包括Dish(菜品)、Menu(菜单)、Record(记录)和Order(订单)四个类,以及一个Main类作为程序入口。

Dish类:

该类表示菜品,包括菜品名称和单价。可以根据菜品的分量计算价格。

包括构造函数用于初始化菜品信息,以及根据分量计算价格和获取菜品名称的方法。

Menu类:

该类表示菜单,包括多个菜品。可以添加新菜品、查找菜品。

包括addDish方法用于添加菜品到菜单中,searchDish方法用于查找菜单中的菜品。

Record类:

该类表示订单记录,包括订单号、菜品、分量、数量等信息。可以计算记录的总价和获取记录的字符串表示。

包括构造函数用于初始化订单记录,计算价格和获取记录字符串的方法。

Order类:

该类表示订单,包括多条订单记录。可以计算订单的总价、添加记录、删除记录等操作。

包括构造函数用于初始化订单,计算总价、添加记录、删除记录和查找记录的方法。

Main类:

该类为程序入口,包括主函数用于接收用户输入并进行相应的菜单操作,直到用户输入"end"结束程序运行。

程序运行流程为:

创建一个空订单对象和一个空菜单对象。

不断接收用户输入,根据输入内容执行相应的菜单操作:

如果输入为菜品名称和单价,则将菜品添加到菜单中。

如果输入为订单号和菜品信息,则添加订单记录到订单中。

如果输入为订单号和"delete"关键字,则删除对应订单记录。

当用户输入"end"时,结束程序运行,并输出订单的总价。

整体而言,该程序实现了一个简单的菜单管理和订单记录功能,可以方便地添加菜品到菜单中,并针对每个订单记录进行增删查操作。

改代码的复杂度分析和类图如下:

菜单4

菜单计价程序-4

分数 100

全屏浏览题目

切换布局

作者 蔡轲

单位 南昌航空大学

本体大部分内容与菜单计价程序-3相同,增加的部分用加粗文字进行了标注。

设计点菜计价程序,根据输入的信息,计算并输出总价格。

输入内容按先后顺序包括两部分:菜单、订单,最后以"end"结束。

菜单由一条或多条菜品记录组成,每条记录一行

每条菜品记录包含:菜名、基础价格 两个信息。

订单分:桌号标识、点菜记录和删除信息、代点菜信息。每一类信息都可包含一条或多条记录,每条记录一行或多行。

桌号标识独占一行,包含两个信息:桌号、时间。

桌号以下的所有记录都是本桌的记录,直至下一个桌号标识。

点菜记录包含:序号、菜名、份额、份数。份额可选项包括:1、2、3,分别代表小、中、大份。

不同份额菜价的计算方法:小份菜的价格=菜品的基础价格。中份菜的价格=菜品的基础价格1.5。小份菜的价格=菜品的基础价格2。如果计算出现小数,按四舍五入的规则进行处理。

删除记录格式:序号 delete

标识删除对应序号的那条点菜记录。

如果序号不对,输出"delete error"

代点菜信息包含:桌号 序号 菜品名称 份额 分数

代点菜是当前桌为另外一桌点菜,信息中的桌号是另一桌的桌号,带点菜的价格计算在当前这一桌。

程序最后按输入的桌号从小到大的顺序依次输出每一桌的总价(注意:由于有代点菜的功能,总价不一定等于当前桌上的菜的价格之和)。

每桌的总价等于那一桌所有菜的价格之和乘以折扣。如存在小数,按四舍五入规则计算,保留整数。

折扣的计算方法(注:以下时间段均按闭区间计算):

周一至周五营业时间与折扣:晚上(17:00-20:30)8折,周一至周五中午(10:30--14:30)6折,其余时间不营业。

周末全价,营业时间:9:30-21:30

如果下单时间不在营业范围内,输出"table " + t.tableNum + " out of opening hours"

参考以下类的模板进行设计(本内容与计价程序之前相同,其他类根据需要自行定义):

菜品类:对应菜谱上一道菜的信息。

Dish {

String name;//菜品名称

int unit_price; //单价

int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) }

菜谱类:对应菜谱,包含饭店提供的所有菜的信息。

Menu {

Dish[] dishs ;//菜品数组,保存所有菜品信息

Dish searthDish(String dishName)//根据菜名在菜谱中查找菜品信息,返回Dish对象。

Dish addDish(String dishName,int unit_price)//添加一道菜品信息

}

点菜记录类:保存订单上的一道菜品记录

Record {

int orderNum;//序号

Dish d;//菜品\\

int portion;//份额(1/2/3代表小/中/大份)

int getPrice()//计价,计算本条记录的价格

}

订单类:保存用户点的所有菜的信息。

Order {

Record[] records;//保存订单上每一道的记录

int getTotalPrice()//计算订单的总价

Record addARecord(int orderNum,String dishName,int portion,int num)//添加一条菜品信息到订单中。

delARecordByOrderNum(int orderNum)//根据序号删除一条记录

findRecordByNum(int orderNum)//根据序号查找一条记录

}

本次课题比菜单计价系列-3增加的异常情况:

1、菜谱信息与订单信息混合,应忽略夹在订单信息中的菜谱信息。输出:"invalid dish"

2、桌号所带时间格式合法(格式见输入格式部分说明,其中年必须是4位数字,月、日、时、分、秒可以是1位或2位数),数据非法,比如:2023/15/16 ,输出桌号+" date error"

3、同一桌菜名、份额相同的点菜记录要合并成一条进行计算,否则可能会出现四舍五入的误差。

4、重复删除,重复的删除记录输出"deduplication :"+序号。

5、代点菜时,桌号不存在,输出"Table number :"+被点菜桌号+" does not exist";本次作业不考虑两桌记录时间不匹配的情况。

6、菜谱信息中出现重复的菜品名,以最后一条记录为准。

7、如果有重复的桌号信息,如果两条信息的时间不在同一时间段,(时段的认定:周一到周五的中午或晚上是同一时段,或者周末时间间隔1小时(不含一小时整,精确到秒)以内算统一时段),此时输出结果按不同的记录分别计价。

8、重复的桌号信息如果两条信息的时间在同一时间段,此时输出结果时合并点菜记录统一计价。前提:两个的桌号信息的时间都在有效时间段以内。计算每一桌总价要先合并符合本条件的饭桌的点菜记录,统一计价输出。

9、份额超出范围(1、2、3)输出:序号+" portion out of range "+份额,份额不能超过1位,否则为非法格式,参照第13条输出。

10、份数超出范围,每桌不超过15份,超出范围输出:序号+" num out of range "+份数。份数必须为数值,最高位不能为0,否则按非法格式参照第16条输出。

11、桌号超出范围[1,55]。输出:桌号 +" table num out of range",桌号必须为1位或多位数值,最高位不能为0,否则按非法格式参照第16条输出。

12、菜谱信息中菜价超出范围(区间(0,300)),输出:菜品名+" price out of range "+价格,菜价必须为数值,最高位不能为0,否则按非法格式参照第16条输出。

13、时间输入有效但超出范围[2022.1.1-2023.12.31],输出:"not a valid time period"

14、一条点菜记录中若格式正确,但数据出现问题,如:菜名不存在、份额超出范围、份数超出范围,按记录中从左到右的次序优先级由高到低,输出时只提示优先级最高的那个错误。

15、每桌的点菜记录的序号必须按从小到大的顺序排列(可以不连续,也可以不从1开始),未按序排列序号的输出:"record serial number sequence error"。当前记录忽略。(代点菜信息的序号除外)

16、所有记录其它非法格式输入,统一输出"wrong format"

17、如果记录以“table”开头,对应记录的格式或者数据不符合桌号的要求,那一桌下面定义的所有信息无论正确或错误均忽略,不做处理。如果记录不是以“table”开头,比如“tab le 55 2023/3/2 12/00/00”,该条记录认为是错误记录,后面所有的信息并入上一桌一起计算。

本次作业比菜单计价系列-3增加的功能:

菜单输入时增加特色菜,特色菜的输入格式:菜品名+英文空格+基础价格+"T"

例如:麻婆豆腐 9 T

菜价的计算方法:

周一至周五 7折, 周末全价。

注意:不同的四舍五入顺序可能会造成误差,请按以下步骤累计一桌菜的菜价:

计算每条记录的菜价:将每份菜的单价按份额进行四舍五入运算后,乘以份数计算多份的价格,然后乘以折扣,再进行四舍五入,得到本条记录的最终支付价格。

最后将所有记录的菜价累加得到整桌菜的价格。

输入格式:

桌号标识格式:table + 序号 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 时间(24小时制格式: HH/MM/SS)

菜品记录格式:

菜名+英文空格+基础价格

如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。

点菜记录格式:序号+英文空格+菜名+英文空格+份额+英文空格+份数注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。

删除记录格式:序号 +英文空格+delete

代点菜信息包含:桌号+英文空格+序号+英文空格+菜品名称+英文空格+份额+英文空格+分数

最后一条记录以“end”结束。

输出格式:

按输入顺序输出每一桌的订单记录处理信息,包括:

1、桌号,格式:table+英文空格+桌号+”:”+英文空格

2、按顺序输出当前这一桌每条订单记录的处理信息,

每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品*份数,序号是之前输入的订单记录的序号。如果订单中包含不能识别的菜名,则输出“** does not exist”,**是不能识别的菜名

如果删除记录的序号不存在,则输出“delete error”

最后按输入顺序一次输出每一桌所有菜品的总价(整数数值)格式:table+英文空格+桌号+“:”+英文空格+当前桌的原始总价+英文空格+当前桌的计算折扣后总价

本题目由于时间安排原因,bug较多且尚未修复,代码及分析如下:

import java.util.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.regex.Pattern;



class Dish
{
String name="";//菜品名称
int unit_price;
boolean special=false;//特色菜,true为是
//单价
int getPrice(int portion) {
int 菜价 = 0;
// 单菜价格
if (portion == 1) {
菜价 = unit_price;
} else if (portion == 2) {
菜价 = (int) Math.ceil(1.0 * unit_price * 3 / 2);
} else if (portion == 3) {
菜价 = unit_price * 2;
}
return 菜价;
}

}
class Menu
{
Dish[] dishs =new Dish[20];
int i=0;//用于记录菜品总数
void addDish(String dishName,int unit_price,Boolean ts)
{

// Dish dish1=new Dish();
dishs[i]=new Dish();
dishs[i].name=dishName;
dishs[i].unit_price=unit_price;
dishs[i].special=ts;
i++;
//return dish1;
}
//菜品数组,保存所有菜品信息
Dish searthDish(String dishName) //根据菜名在菜谱中查找菜品信息,返回Dish对象。
{
int j=0;
int flag=0;
for(j=i-1;j>=0;j--)//从未末端开始查找比对
{
if(dishName.compareTo(dishs[j].name)==0)
{
flag=1;
break;
}
}
if(flag==1)
return dishs[j];
else
{
//麻辣鸡丝 does not exist
System.out.println(dishName+" does not exist");
return null;
}
}
}
class Record
{
Dish d=new Dish();//菜品
int num=0;//份数
int tablenum=0;//桌号//没什么用
int orderNum=0;//序号\
int portion=0;

boolean self=true;
//份额(1/2/3代表小/中/大份)
int getPrice()
{
int n=0;
n=num*d.getPrice(portion);

return n;
}
}

class Order
{
Record[] records=new Record[18];
int j=0;
int[] deletenum=new int[30];
//添加一条菜品信息到订单中。
void addARecord(int tablenum,int orderNum,String dishName,int portion,int num,boolean self)//添加一条菜品信息到订单中。
{
//1 麻婆豆腐 2 2
records[j]=new Record();
records[j].tablenum=tablenum;
records[j].portion=portion;
records[j].num=num;
records[j].self=self;
records[j].orderNum=orderNum;
records[j].d.name=dishName;
j++;
}

boolean srarchdelete(int orderNum)//找到返回true
{
int i=0;
for(i=0;i<50;i++)
{
if(deletenum[i]!=0)
{
if(orderNum==deletenum[i])
{
return true;
}
}
else break;
}
deletenum[i]=orderNum;
if(i==0)
{
return false;
}
return false;
}
void delARecordByOrderNum(int orderNum,table t)//根据序号删除一条记录
//试试直接总价减去删除菜
{
if(srarchdelete(orderNum)==false)
{
for(int i=0;i<j;i++)
{
if(t.selforder.records[i].orderNum==orderNum)
{
t.selforder.records[i].num=0;
}

}
}
else//情况4
{
System.out.print("deduplication ");
System.out.println(orderNum);
}
}
void srarchrecord(Record g,int k)
{
int i = 0;
while (i < k && !(g.d.name.equals(records[i].d.name) && g.portion == records[i].portion && records[i].self)) {
i++;
}
if (i < k) {
records[i].num += g.num;
g.num = 0;
}


}
}
class table
{
String time;//点菜时间//2023/3/22 12/2/3
int tablenum;//桌号
int year=0;
int month=0;
int day=0;
int ww=0;
int hh=0;
int mm=0;
int ss=0;
int truesum=0;
double count=0;
int sumdish=0;
double specialcount=1;
Order selforder=new Order();
boolean flag=false;
int sum=0;
int k=0;

void input(String time,int b)//预处理
{
String[] arr1=time.split(" ");
int blank = time.length() - time.replace(" ", "").length();

//桌号
if(blank!=3||!arr1[1].matches("^[1-9][0-9]{0,}$")||arr1.length!=4)
{
System.out.println("wrong format");
}

// 验证时间格式的正则表达式
String timeRegex = "^([0-9]{4}/[0-9]{1,2}/[0-9]{1,2}) ([0-9]{1,2}/[0-9]{1,2}/[0-9]{1,2})$";
// 验证日期格式的正则表达式
String dateRegex = "^(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})/((([0]{0,1}[13578]|1[02])/([0]{0,1}[1-9]|[12][0-9]|3[01]))|(([0]{0,1}[469]|11)/([0]{0,1}[1-9]|[12][0-9]|30))|([0]{0,1}2/([1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})([48]|[0]{0,1}[2468][048]|[0]{0,1}[13579][26])|(([48]|[2468][048]|[3579][26])00))/[0]{0,1}2/29)$";
// 验证时间格式的正则表达式
String timeFormatRegex = "^([0-9]|([01][0-9])|(2[0-3]))/([0-9]|([0-5][0-9]))/([0-9]|([0-5][0-9]))$";

this.time = arr1[2] + " " + arr1[3];
tablenum = Integer.parseInt(arr1[1]);

if (tablenum <= 55 && tablenum >= 1) {
if (Pattern.matches(timeRegex, this.time)) {
if (Pattern.matches(dateRegex, arr1[2]) && Pattern.matches(timeFormatRegex, arr1[3])) {
boolean flag1 = judgetime1();
if (flag1) {
timechange();
jscount();
pdflag();
if (b == 1) {
System.out.println("wrong format");
}
} else {
System.out.println("not a valid time period");
}
} else {
System.out.println(tablenum + " date error");
}
} else {
System.out.println("wrong format");
}
} else {
System.out.println(arr1[1] + " table num out of range");
}
}



boolean judgetime1() {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH/mm/ss");
dateFormat.setLenient(false);

try {
dateFormat.parse(time);
return true;
} catch (ParseException e) {
return false;
}
}

void getTotalPrice()//计算桌总价
{
if(flag)
{
int j=selforder.j;
int x = j - 1;
while (x >= 0) {
selforder.srarchrecord(selforder.records[x], x);
x--;
}
for(int i=0;i<j;i++)
{
int xy=selforder.records[i].getPrice();
truesum=xy+truesum;

sum+=(int)(xy*count+0.5);
}
System.out.print("table ");
System.out.print(tablenum);
System.out.print(": ");
System.out.print(truesum);
System.out.print(" ");
System.out.println(sum);
}
}
void jscount() {
specialcount = (ww >= 1 && ww <= 5) ? 0.7 : 1;

if (ww >= 1 && ww <= 5) {
if (hh >= 17 && hh < 20) {
count = 0.8;
} else if ((hh == 20 && mm < 30) || (hh == 20 && mm == 30 && ss == 0)) {
count = 0.8;
} else if ((hh >= 11 && hh <= 13) || (hh == 10 && mm >= 30) || (hh == 14 && mm < 30) || (hh == 14 && mm == 30 && ss == 0)) {
count = 0.6;
}
} else {
if ((hh >= 10 && hh <= 20) || (hh == 9 && mm >= 30) || (hh == 21 && mm < 30) || (hh == 21 && mm == 30 && ss == 0)) {
count = 1.0;
}
}
}

void pdflag()//判断时间是否正确
{
if(count!=0)
flag=true;
else {
System.out.print("table ");
System.out.print(tablenum);
System.out.println(" out of opening hours.");
flag=false;
}
}
void timechange() {
// 2023/3/22 12/2/3
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/M/d H/m/s");
LocalDateTime dateTime = LocalDateTime.parse(time, formatter);

year = dateTime.getYear();
month = dateTime.getMonthValue();
day = dateTime.getDayOfMonth();

LocalDate date = LocalDate.of(year, month, day);
ww = date.getDayOfWeek().getValue();
if (ww == 7) {
ww = 1;
} else {
ww++;
}

hh = dateTime.getHour();
mm = dateTime.getMinute();
ss = dateTime.getSecond();
}
boolean searthtable(table[]t,int num,int p)
{
for(int i=0;i<50;i++)
{
if(t[i]!=null&&i!=p&&t[i].tablenum==num&&t[i].flag)
return true;

else
break;
}
System.out.print("Table number: ");
System.out.print(num);
System.out.println(" does not exist.");
return false;
}
int searchtime(table[]t,table a,int sumtable)//若找到返回对应桌,找不到返回下一个空桌
{
//(时段的认定:周一到周五的中午或晚上是同一时段,或者周末时间间隔1小时(不含一小时整,精确到秒)
for (int i = 0; i < sumtable; i++) {
if (isSameTable(a, t[i]) && isSameDate(a, t[i]) && isSameTimePeriod(a, t[i])) {
return i;
}
}
return sumtable;
}

boolean isSameTable(table a, table b) {
return a.tablenum == b.tablenum;
}

boolean isSameDate(table a, table b) {
return a.year == b.year && a.day == b.day;
}

boolean isSameTimePeriod(table a, table b) {
if (isWeekday(a)) {
return (a.hh <= 14 && b.hh <= 14) || (a.hh > 14 && b.hh > 14);
} else {
int timeDifference = Math.abs((a.hh - b.hh) * 60 * 60 + (a.mm - b.mm) * 60 + (a.ss - b.ss));
return timeDifference < 60 * 60;
}
}

boolean isWeekday(table a) {
return a.ww >= 1 && a.ww <= 5;
}

}

class Worn//错误判断,错误b[i]==1
{
void worninput(String[]a,int num,int[]b)
{
//boolean flag1=true;

for(int i=0;i<num;i++)
{
String[] arr=a[i].split(" ");
boolean flag=false;
if(arr.length>5)
{
b[i]=1;
}

if(a[i].matches("^[\u4e00-\u9fa5]{1,4} ([1-9][0-9]{0,2}) [T]$")==true)
{
flag=true;
}
else if(a[i].matches("^[\u4e00-\u9fa5]{1,} ([1-9][0-9]{0,2})$")==true)
{
flag=true;
}
else if ("table".equals(arr[0]) && arr[1].matches("^([1-9][0-9]*)$") && a[i].split("\\s+").length == 4)
{
flag = true;
}

else if(a[i].matches("^([1-9][0-9]{0,1}) [1-9][0-9]{0,2} [\u4e00-\u9fa5]{1,} [1-9] ([1-9][0-9]{0,1})$")==true)
{
flag=true;
}
else if(a[i].matches("^[1-9][0-9]{0,2} [\u4e00-\u9fa5]{1,} [1-9] ([1-9][0-9]{0,1})$")==true)
{
flag=true;
}



else if(a[i].matches("^([1-9][0-9]{0,1}) delete$")==true)//删菜
{
flag=true;
}
else if(a[i].matches("^end$")==true)//结尾
{
flag=true;
}


if(flag==false)
{
b[i]=1;
}
}
}
}

public class Main {
public static void main(String[] args) {
try (Scanner in = new Scanner(System.in)) {
String[] a=new String[30];
int[]b=new int[30];
Menu c=new Menu();
table[] t=new table[30];
Dish g=new Dish();
int lastdish=0;
int dc1=0,dc2=0,dc3=0,dd1=0,dd2=0,dd3=0,dd4=0;
int inputnum=0,h;
int i=0;//桌号
int j=0;//菜数
int p=0;//当前处理桌号
a[0]=in.nextLine();
b[0]=0;
while(!a[inputnum].equals("end"))
{
inputnum++;
a[inputnum]=in.nextLine();
b[inputnum]=0;
}
Worn w=new Worn();
w.worninput(a,inputnum,b);
for(h=0;h<inputnum;h++)
{
boolean flagerror=false;
String[] arr = a[h].split(" ");
if(arr.length==4||arr[0].charAt(0)=='t')
{

if(arr[0].equals("table"))//加桌
{
flagerror=true;
lastdish=0;
table x=new table();
x.input(a[h],b[h]);
if(i!=0)
p=t[i-1].searchtime(t,x,i);
if(p==i)//加新桌
{
t[i]=new table();
t[p]=x;
i++;
lastdish=0;//初始化
if(t[p].flag)
System.out.println("table "+t[p].tablenum+": ");
}
else
{
if(t[p].flag)
System.out.println("table "+t[p].tablenum+": ");
lastdish=0;
}

}
else if(arr[0].matches("^[1-9][0-9]{0,1}$"))//自己点菜
{
if(b[h]==1)
{
flagerror=true;
if(i!=0&&t[p].flag)
{
System.out.println("wrong format");
}
continue;
}
dc1=Integer.parseInt(arr[0]);
dc2=Integer.parseInt(arr[2]);
dc3=Integer.parseInt(arr[3]);
if(i!=0&&t[p].flag)
{

if(i!=0)
{
if(dc1<=lastdish)
{
System.out.print("record ");
System.out.print("serial ");
System.out.print("number ");
System.out.print("sequence ");
System.out.print("error\n");

}
else
{
t[p].selforder.addARecord(0,dc1,arr[1],dc2,dc3,true);
g=c.searthDish(arr[1]);

if(g!=null&&t[p].flag)
{

if(dc3>15)
{
System.out.print(dc1);
System.out.print(" num ");
System.out.print("out ");
System.out.print("of ");
System.out.print("range ");
System.out.print(dc3);
System.out.print("\n");

}
else if(dc2>3&&dc2<10||dc2<=0&&dc2>-10)//情况9
{
System.out.print(dc1);
System.out.print(" portion ");
System.out.print("out ");
System.out.print("of ");
System.out.print("range ");
System.out.print(dc2);
System.out.print("\n");
}
else
{
t[p].selforder.records[t[p].k].d=g;
int x=t[p].selforder.records[t[p].k].getPrice();
lastdish=dc1;
System.out.print(dc1);
System.out.print(" ");
System.out.print(arr[1]);
System.out.print(" ");
System.out.print(x);
System.out.print("\n");

}

}
t[p].k++;

}
}

}
}
else
{
System.out.println("wrong format");
flagerror=true;
}

}

else if(arr.length==5)//代点
{
// 1 4 麻婆豆腐 1 1
if(b[h]==1)
{
flagerror=true;
if(i!=0&&t[p].flag)
{
System.out.println("wrong format");
}
continue;
}
dd1=Integer.parseInt(arr[0]);
dd2=Integer.parseInt(arr[1]);
dd3=Integer.parseInt(arr[3]);
dd4=Integer.parseInt(arr[4]);
if(t[p].searthtable(t,dd1,p)==true)
{
t[p].selforder.addARecord(dd2, dd1, arr[2], dd3,dd4,false);
g=c.searthDish(arr[2]);
if(g!=null)
{
t[p].selforder.records[t[p].k].d=g;
int x=t[p].selforder.records[t[p].k].getPrice();
System.out.println(dd2+" table "+t[p].tablenum+" pay for table "+dd1+" "+x);
}
//k++;
t[p].k++;
}
}
else if(arr.length==2)
{
if(arr[1].equals("delete"))//删菜
{

if(i!=0)
{
if(b[h]==1)
{
flagerror=true;
if(i!=0)
{
System.out.println("wrong format");
}
continue;
}
if(t[p].flag)
t[p].selforder.delARecordByOrderNum(Integer.parseInt(arr[0]),t[p]);
}
}
else//加菜
{
if(b[h]==1)
{
flagerror=true;
System.out.println("wrong format");
continue;
}
if(i!=0&&t[p].flag)//情况1
{
System.out.println("invalid dish");
}
else
{
if(Integer.parseInt(arr[1])>0&&Integer.parseInt(arr[1])<300)
{
c.addDish(arr[0], Integer.parseInt(arr[1]),false);
j++;
}
else
{
System.out.println(arr[0]+" price out of range "+arr[1]);
}
}
}
}
else if(arr.length==3)//特色菜
{
if(b[h]==1)
{
flagerror=true;
System.out.println("wrong format");
continue;
}
if(i!=0&&t[p].flag)
{
System.out.println("invalid dish");
}
else
{
if(arr[2].equals("T"))
{
if(Integer.parseInt(arr[1])>0&&Integer.parseInt(arr[1])<300)
{
c.addDish(arr[0], Integer.parseInt(arr[1]),true);
j++;
}
else
{
System.out.println(arr[0]+" price out of range "+arr[1]);
}
}
}
}
}
for(int l=0;l<i;l++)
{
t[l].getTotalPrice();
}
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}

上述代码是一个简单的餐厅点餐系统的 Java 实现。以下是对代码的简要分析:

类定义部分

Dish 类:表示菜品,包括菜品名称、单价、是否是特色菜等属性,以及计算菜品价格的方法。

Menu 类:表示菜单,包括菜品数组和添加、查找菜品的方法。

Record 类:表示订单中的一条菜品信息,包括菜品、份数、桌号、序号等属性,以及计算菜品总价的方法。

Order 类:表示订单,包括记录多条菜品信息、添加、删除记录的方法。

table 类:表示餐桌,包括点菜时间、桌号、订单信息等属性,以及对时间和桌号进行处理的方法。

Worn 类:用于错误判断的辅助类。

主程序部分

main 方法:包括整个程序的主要逻辑,包括读取输入、创建菜单、处理订单等功能。

主要逻辑

读取输入,根据输入内容判断是新增桌号、自己点菜、代点菜、加菜、删菜等操作。

根据输入操作调用相应的类的方法进行处理,比如添加菜品、计算菜品价格、记录订单信息等。

输出结果,包括餐桌总价、菜品价格、错误信息等。

以上是对代码的简要分析,主要涉及了餐厅点餐系统的基本功能实现。

复杂度分析和类图如下:

菜单5

 菜单计价程序-5

分数 100

全屏浏览题目

切换布局

作者 蔡轲

单位 南昌航空大学

本题在菜单计价程序-3的基础上增加了部分内容,增加的内容用加粗字体标识。

注意不是菜单计价程序-4,本题和菜单计价程序-4同属菜单计价程序-3的两个不同迭代分支


设计点菜计价程序,根据输入的信息,计算并输出总价格。

 

输入内容按先后顺序包括两部分:菜单、订单,最后以"end"结束。

 

菜单由一条或多条菜品记录组成,每条记录一行

 

每条菜品记录包含:菜名、基础价格  三个信息。

 

订单分:桌号标识、点菜记录和删除信息、代点菜信息。每一类信息都可包含一条或多条记录,每条记录一行或多行。

 

桌号标识独占一行,包含两个信息:桌号、时间。

 

桌号以下的所有记录都是本桌的记录,直至下一个桌号标识。

 

点菜记录包含:序号、菜名、份额、份数。份额可选项包括:1、2、3,分别代表小、中、大份。

 

不同份额菜价的计算方法:小份菜的价格=菜品的基础价格。中份菜的价格=菜品的基础价格1.5。小份菜的价格=菜品的基础价格2。如果计算出现小数,按四舍五入的规则进行处理。

 

删除记录格式:序号  delete

 

标识删除对应序号的那条点菜记录。

 

如果序号不对,输出"delete error"

 

代点菜信息包含:桌号 序号 菜品名称 口味度 份额 份数

 

代点菜是当前桌为另外一桌点菜,信息中的桌号是另一桌的桌号,带点菜的价格计算在当前这一桌。

 

程序最后按输入的先后顺序依次输出每一桌的总价(注意:由于有代点菜的功能,总价不一定等于当前桌上的菜的价格之和)。

 

每桌的总价等于那一桌所有菜的价格之和乘以折扣。如存在小数,按四舍五入规则计算,保留整数。

 

折扣的计算方法(注:以下时间段均按闭区间计算):

 

周一至周五营业时间与折扣:晚上(17:00-20:30)8折,周一至周五中午(10:30--14:30)6折,其余时间不营业。

 

周末全价,营业时间:9:30-21:30

 

如果下单时间不在营业范围内,输出"table " + t.tableNum + " out of opening hours"

 

参考以下类的模板进行设计:菜品类:对应菜谱上一道菜的信息。

 

Dish {    

 

   String name;//菜品名称    

 

   int unit_price;    //单价    

 

   int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份)    }

 

菜谱类:对应菜谱,包含饭店提供的所有菜的信息。

 

Menu {

 

   Dish[] dishs ;//菜品数组,保存所有菜品信息

 

   Dish searthDish(String dishName)//根据菜名在菜谱中查找菜品信息,返回Dish对象。

 

   Dish addDish(String dishName,int unit_price)//添加一道菜品信息

 

}

 

点菜记录类:保存订单上的一道菜品记录

 

Record {

 

   int orderNum;//序号\\

 

   Dish d;//菜品\\

 

   int portion;//份额(1/2/3代表小/中/大份)\\

 

   int getPrice()//计价,计算本条记录的价格\\

 

}

 

订单类:保存用户点的所有菜的信息。

 

Order {

 

   Record[] records;//保存订单上每一道的记录

 

   int getTotalPrice()//计算订单的总价

 

   Record addARecord(int orderNum,String dishName,int portion,int num)//添加一条菜品信息到订单中。

 

   delARecordByOrderNum(int orderNum)//根据序号删除一条记录

 

   findRecordByNum(int orderNum)//根据序号查找一条记录

 

}

 

### 输入格式:

 

桌号标识格式:table + 序号 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 时间(24小时制格式: HH/MM/SS)

 

菜品记录格式:

 

菜名+英文空格+基础价格

 

如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。

 

点菜记录格式:序号+英文空格+菜名+英文空格+份额+英文空格+份数注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。

 

删除记录格式:序号 +英文空格+delete

 

代点菜信息包含:桌号+英文空格+序号+英文空格+菜品名称+英文空格+份额+英文空格+分数

 

最后一条记录以“end”结束。

 

### 输出格式:

 

按输入顺序输出每一桌的订单记录处理信息,包括:

 

1、桌号,格式:table+英文空格+桌号+”:”

 

2、按顺序输出当前这一桌每条订单记录的处理信息,

 

每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品\*份数,序号是之前输入的订单记录的序号。如果订单中包含不能识别的菜名,则输出“\*\* does not exist”,\*\*是不能识别的菜名

 

如果删除记录的序号不存在,则输出“delete error”

 

最后按输入顺序一次输出每一桌所有菜品的总价(整数数值)格式:table+英文空格+桌号+“:”+英文空格+当前桌的总价

 

以上为菜单计价系列-3的题目要求,加粗的部分是有调整的内容。本次课题相比菜单计价系列-3新增要求如下:

 

1、菜单输入时增加特色菜,特色菜的输入格式:菜品名+英文空格+口味类型+英文空格+基础价格+"T"

例如:麻婆豆腐 川菜 9 T

菜价的计算方法:

周一至周五 7折, 周末全价。

特色菜的口味类型:川菜、晋菜、浙菜

川菜增加辣度值:辣度0-5级;对应辣度水平为:不辣、微辣、稍辣、辣、很辣、爆辣;

晋菜增加酸度值,酸度0-4级;对应酸度水平为:不酸、微酸、稍酸、酸、很酸;

浙菜增加甜度值,甜度0-3级;对应酸度水平为:不甜、微甜、稍甜、甜;    

例如:麻婆豆腐 川菜 9 T

输入订单记录时如果是特色菜,添加口味度(辣/酸/甜度)值,格式为:序号+英文空格+菜名+英文空格+口味度值+英文空格+份额+英文空格+份数

例如:1 麻婆豆腐 4 1 9

单条信息在处理时,如果口味度超过正常范围,输出"spicy/acidity/sweetness num out of range : "+口味度值,spicy/acidity/sweetness(辣度/酸度/甜度)根据菜品类型择一输出,例如:

acidity num out of range : 5

输出一桌的信息时,按辣、酸、甜度的顺序依次输出本桌菜各种口味的口味度水平,如果没有某个类型的菜,对应的口味(辣/酸/甜)度不输出,只输出已点的菜的口味度。口味度水平由口味度平均值确定,口味度平均值只综合对应口味菜系的菜计算,不做所有菜的平均。比如,某桌菜点了3份川菜,辣度分别是1、3、5;还有4份晋菜,酸度分别是,1、1、2、2,辣度平均值为3、酸度平均值四舍五入为2,甜度没有,不输出。

一桌信息的输出格式:table+英文空格+桌号+:+英文空格+当前桌的原始总价+英文空格+当前桌的计算折扣后总价+英文空格+"川菜"+数量+辣度+英文空格+"晋菜"+数量+酸度+英文空格+"浙菜"+数量+甜度。

如果整桌菜没有特色菜,则只输出table的基本信息,格式如下,注意最后加一个英文空格:

table+英文空格+桌号+:+英文空格+当前桌的原始总价+英文空格+当前桌的计算折扣后总价+英文空格

例如:table 1: 60 36 川菜 2 爆辣 浙菜 1 微甜

计算口味度时要累计本桌各类菜系所有记录的口味度总和(每条记录的口味度乘以菜的份数),再除以对应菜系菜的总份数,最后四舍五入。

注:本题要考虑代点菜的情况,当前桌点的菜要加上被其他桌代点的菜综合计算口味度平均值。

 

 

2、考虑客户订多桌菜的情况,输入时桌号时,增加用户的信息:

格式:table+英文空格+桌号+英文空格+":"+英文空格+客户姓名+英文空格+手机号+日期(格式:YYYY/MM/DD)+英文空格+ 时间(24小时制格式: HH/MM/SS)

例如:table 1 : tom 13670008181 2023/5/1 21/30/00

约束条件:客户姓名不超过10个字符,手机号11位,前三位必须是180、181、189、133、135、136其中之一。

输出结果时,先按要求输出每一桌的信息,最后按字母顺序依次输出每位客户需要支付的金额。不考虑各桌时间段的问题,同一个客户的所有table金额都要累加。

输出用户支付金额格式:

用户姓名+英文空格+手机号+英文空格+支付金额

 

 

注意:不同的四舍五入顺序可能会造成误差,请按以下步骤累计一桌菜的菜价:

 

计算每条记录的菜价:将每份菜的单价按份额进行四舍五入运算后,乘以份数计算多份的价格,然后乘以折扣,再进行四舍五入,得到本条记录的最终支付价格。

将所有记录的菜价累加得到整桌菜的价格。

输入格式:

桌号标识格式:table + 序号 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 时间(24小时制格式: HH/MM/SS)

 

菜品记录格式:

 

菜名+口味类型+英文空格+基础价格

 

如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。

 

点菜记录格式:序号+英文空格+菜名+英文空格+辣/酸/甜度值+英文空格+份额+英文空格+份数 注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。辣/酸/甜度取值范围见题目中说明。

 

删除记录格式:序号 +英文空格+delete

 

代点菜信息包含:桌号+英文空格+序号+英文空格+菜品名称**+英文空格+辣/酸/甜度值+**英文空格+份额+英文空格+分数

 

最后一条记录以“end”结束。

输出格式:

按输入顺序输出每一桌的订单记录处理信息,包括:

 

1、桌号,格式:table+英文空格+桌号+“:”+英文空格

 

2、按顺序输出当前这一桌每条订单记录的处理信息,

 

每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品\*份数,序号是之前输入的订单记录的序号。如果订单中包含不能识别的菜名,则输出“\*\* does not exist”,\*\*是不能识别的菜名

 

如果删除记录的序号不存在,则输出“delete error”

 

之后按输入顺序一次输出每一桌所有菜品的价格(整数数值),

格式:table+英文空格+桌号+“:”+英文空格+当前桌的计算折扣后总价+英文空格+辣度平均值+英文空格+酸度平均值+英文空格+甜度平均值+英文空格

 

最后按拼音顺序输出每位客户(不考虑客户同名或拼音相同的情况)的支付金额,格式: 用户姓名+英文空格+手机号+英文空格+支付总金额,按输入顺序排列。

本次题目仍然存在一些bug,主要出现在删除问题和带点菜的逻辑问题中,最终也只得到了80分需要后续改进

代码如下:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Scanner;
import java.util.regex.*;

public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
Menu menu=new Menu();
Dish d;
String a,b,c ;
a = in.next();
while(!a.equals("end"))
{
if(!a.startsWith("t"))//table t开头
{
String buff;
buff=in.nextLine();
String [] buffer = buff.split(" ");

String pattern = "^\\s*[\\u4e00-\\u9fa5]+\\s\\d+\\s?[A-Za-z]?$";// " 川菜 12 T"
boolean isMatch = Pattern.matches(pattern, buff);
if(isMatch)
{
if( buffer[3].equals("T") )//特色菜 buffer[3].equals('T') 是否为特色菜 T标志
{
d=new Dish(a,buffer[1],buffer[2],buffer[3]);
menu.add(d);
}
}
else if(!isMatch){
int price=Integer.parseInt(buffer[1]);
d=new Dish(a,price);
menu.add(d);
}

}
else
break;
a=in.next();

}
//以下为订单信息,a此时为"table"才会进入判断

ArrayList<Order> orders = new ArrayList<Order>();
while(a.equals("table")) //(!a.equals("end")) 旧
{
//int numx = Integer.parseInt(a); 非点菜人信息
// if(a.equals("table"))

int table=in.nextInt();//接收第几桌
// 接受订单信息

a=in.next(); //接受分号
a=in.next(); //用来记录点菜人的名字

b=in.next(); //用来记录点菜人的电话

c=in.next(); //接收日期
String e = in.next(); //接收时间

//传入
Order order = new Order(menu,table);
orders.add(order);
order.orderP=a;
order.dianhua=b;
order.account(c,e);

if(order.acc==0)//非营业时间
{
System.out.print("table ");
System.out.print(table);
System.out.println(" out of opening hours");
// System.out.println("table "+table+" out of opening hours");
a=in.next();
continue;//不进行下面的操作直接对下一组进行操作
}else
{

}
if(order.orderP.length()<=10&&order.dianhua.length()==11)//检验点菜的格式是不是正确的
{
boolean isMatch = order.dianhua.matches("^(180|181|189|133|135|136)\\d{8}$");

if(isMatch)//手机号11位,前三位必须是180、181、189、133、135、136其中之一
{

System.out.print("table ");
System.out.print(table);
System.out.println(": ");
//System.out.println("table "+table+": ");
}
else
{
System.out.print("wrong ");
System.out.println("format");
}
}
else
{
System.out.print("wrong ");
System.out.println("format");
}


for (;;)//循环执行点菜
{
a=in.next();

if(a.equals("end"))//退出点菜条件
{
break;
}
else if(a.equals("table"))
{
break;
}
String m=in.nextLine();
String[] p = m.split(" ");

if (m.matches("^\\s\\d\\s[\\u4e00-\\u9fa5]+\\s\\d\\s\\d\\s\\d$")) {//给其他桌点特色菜

int orderNum = Integer.parseInt(p[1]);//这个是点菜的序号
String dishName = p[2];
int dudu = Integer.parseInt(p[3]);
int portion = Integer.parseInt(p[4]);
int num = Integer.parseInt(p[5]);
//查找是否有此菜名
d = menu.searthDish(dishName);//接受菜品
if(d==null)//未找到,说明没有该菜品
System.out.println(dishName+" does not exist");
else
{//找到了,添加订单
if(d.kowei.equals("川菜"))//辣度0-5级;对应辣度水平为:不辣、微辣、稍辣、辣、很辣、爆辣;
{
if(dudu>5)
{
System.out.print("spicy num out of range ");
System.out.println(": " + dudu);

continue;
}
}
if(d.kowei.equals("晋菜"))//酸度0-4级;对应酸度水平为:不酸、微酸、稍酸、酸、很酸;
{
if(dudu>4)
{
System.out.print("acidity num out of range ");
System.out.println(": " + dudu);
continue;
}
}
if(d.kowei.equals("浙菜"))//甜度0-3级;对应酸度水平为:不甜、微甜、稍甜、甜;
{
if(dudu>3)
{
System.out.print("sweetness num out of range ");
System.out.println(": " + dudu);
continue;
}
}
Record r = order.addARecord(orderNum, dishName,dudu, portion, num);
System.out.print(orderNum + " table " + table + " pay for table " + a + " ");
System.out.println(r.getPrice());

//这里的a是给别的桌子点菜的桌位号
}

}
else if (m.matches("^\\s[\\u4e00-\\u9fa5]+\\s\\d\\s\\d\\s\\d$")) {//给自己点特色菜


int orderNum = Integer.parseInt(a);
String dishName = p[1];//这个是菜名
int dudu = Integer.parseInt(p[2]);//这个是口味
int portion = Integer.parseInt(p[3]);//这个是份额
int num = Integer.parseInt(p[4]);//这个是份数
d = menu.searthDish(dishName);
if(d==null)//菜单没有这道菜
{
System.out.println(dishName+" does not exist");
}
else
{
if(d.kowei.equals("川菜"))//辣度0-5级;对应辣度水平为:不辣、微辣、稍辣、辣、很辣、爆辣;
{
if(dudu>5)
{
System.out.println("spicy num out of range "+":"+dudu);

continue;
}
}
if(d.kowei.equals("晋菜"))//酸度0-4级;对应酸度水平为:不酸、微酸、稍酸、酸、很酸;
{
if(dudu>4)
{
System.out.println("acidity num out of range "+":"+dudu);
continue;
}
}
if(d.kowei.equals("浙菜"))//甜度0-3级;对应酸度水平为:不甜、微甜、稍甜、甜;
{
if(dudu>3)
{
System.out.println("sweetness num out of range "+":"+dudu);
continue;
}
}

Record r = order.addARecord (orderNum, dishName,dudu,portion, num);
System.out.println(orderNum+" "+dishName+" "+r.getPrice());
}
// 执行第二种格式的操作
}
else if (m.matches("^\\s[\\u4e00-\\u9fa5]+\\s\\d\\s\\d$")) {//给自己点普通菜

int orderNum = Integer.parseInt(a);
String dishName = p[1];
int portion = Integer.parseInt(p[2]);
int num = Integer.parseInt(p[3]);
//查找是否有此菜名
d = menu.searthDish(dishName);//接受菜品
if(d==null)//未找到,说明没有该菜品
System.out.println(dishName+" does not exist");
else
{//找到了,添加订单
Record r = order.addARecord(orderNum, dishName, portion, num);
System.out.println(orderNum+" "+dishName+" "+r.getPrice());
}


}
else if(m.matches("^\\sdelete$")){//删除菜
order.delARecordByOrderNum(Integer.parseInt(a));
}

}
}

if(Order.panduanacc()!=0)//在营业时间 往下执行
{

Order [] dingdan = new Order[50];
int in_num=0;

for(int i=0;i<orders.size();i++)
{
dingdan[in_num]=new Order();
dingdan[in_num]=orders.get(i);
in_num=in_num+1;
orders.get(i).yuanjia=orders.get(i).getTotalPrice();
orders.get(i).zhehoujia=orders.get(i).getZhegoujia();

System.out.print("table " + orders.get(i).table + ": ");
System.out.print(orders.get(i).yuanjia + " ");
System.out.print(orders.get(i).zhehoujia);


orders.get(i).chuancaide();
orders.get(i).jicaide();

orders.get(i).zhecaide();

String[] tasteLevels = {" 不辣", " 微辣", " 稍辣", " 辣", " 很辣", " 爆辣"};
String[] sourLevels = {" 不酸", " 微酸", " 稍酸", " 酸", " 很酸"};
String[] sweetLevels = {" 不甜", " 微甜", " 稍甜", " 甜"};

if(orders.get(i).zhela_avg==-1 && orders.get(i).jila_avg==-1 && orders.get(i).chuanla_avg==-1)
{
System.out.print(' ');
}

if(orders.get(i).chuanla_avg!=-1)
{
System.out.print( " 川菜 " + orders.get(i).chuancai + tasteLevels[orders.get(i).chuanla_avg]);
// System.out.print(orders.get(i).chuanla_avg);
}

if(orders.get(i).jila_avg!=-1)
{
System.out.print(" 晋菜 " + orders.get(i).jicai + sourLevels[orders.get(i).jila_avg]);
// System.out.print(orders.get(i).jila_avg);
}

if(orders.get(i).zhela_avg!=-1)
{
System.out.print(" 浙菜 " +orders.get(i).zhecai + sweetLevels[orders.get(i).zhela_avg]);
// System.out.print(orders.get(i).zhela_avg);
}

System.out.print("\n");
}

Order temp = new Order();
for(int j=0;j<in_num-1;j++)
{
for(int k=0;k<in_num-1-j;k++)
{
if(((dingdan[k].orderP).compareTo(dingdan[k+1].orderP))>0)
{
temp=dingdan[k+1];
dingdan[k+1]=dingdan[k];
dingdan[k]=temp;
}
}
}//按名字的次序
for(int i=0;i<orders.size()&&dingdan[i]!=null;i++)
{
for(int j=i+1;j<orders.size()&&dingdan[j]!=null;j++)
{
if(dingdan[i].orderP.equals(dingdan[j].orderP))
{
dingdan[i].zhehoujia+=dingdan[j].zhehoujia;
dingdan[j]=null;
}
}
}
for(int i=0;i<orders.size()&&dingdan[i]!=null;i++)
{
System.out.println(dingdan[i].orderP+" "+dingdan[i].dianhua+" "+dingdan[i].zhehoujia);
}
in.close();
}

}
}
//菜品类:对应菜谱上一道菜的信息。
class Dish {
String name;// 菜品名称
int unit_price; // 单价
String kowei=null;//这个是特色菜的口味
int dudu;//这个是记录点的这个菜的度
float acc=0.7f;//这个是特色菜在周一到周五的折扣
String isT=null;//特色菜的标记
Dish(String name,int price)
{
this.name = name;
this.unit_price = price;
}
Dish(String name,String kowei,String price,String isT)// 0123
{
this.name = name;
this.kowei = kowei;

this.unit_price = Integer.parseInt(price);
this.isT = isT;
}
int getPrice(int portion)
{
// 计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份)
float bl[]= {1,1.5f,2};
return Math.round(unit_price*bl[portion-1]);
}
}
//菜谱类:对应菜谱,包含饭店提供的所有菜的信息。
class Menu {
ArrayList<Dish> dishs = new ArrayList<Dish>();// 菜品数组,保存所有菜品信息
public void add(Dish dish)
{
//菜单加一道菜
for(int i=0;i<dishs.size();i++)
{
if(dish.name.equals(dishs.get(i).name))
{
//找到了相同菜名,就替换
dishs.set(i, dish);//这里是重新的覆盖
return ;
}
}
//未找到相同菜名,就增加
dishs.add(dish);
}
Dish searthDish(String dishName)
{
// 根据菜名在菜谱中查找菜品信息,返回Dish对象。
for(int i=0;i<dishs.size();i++)
{
if(dishs.get(i).name.equals(dishName))
return dishs.get(i);
}
return null;
}
}
//点菜记录类:保存订单上的一道菜品记录
class Record {
int orderNum;//序号
Dish d;// 菜品
int portion;// 份额(1/2/3代表小/中/大份)
int num;//份数1,2,3,4,5
int kouwei=-1;
public Record(int orderNum,Dish d,int portion,int num)
{
this.orderNum=orderNum;
this.d=d;
this.portion=portion;
this.num=num;
}
public Record(int orderNum,Dish d,int dudu,int portion,int num)
{
this.orderNum=orderNum;
this.d=d;
this.kouwei=dudu;
this.d.dudu=dudu;
this.portion=portion;
this.num=num;
}
int getPrice()
{
// 计价,计算本条记录的价格
return d.getPrice(portion)*num;
}
}

//订单类:保存用户点的所有菜的信息

class Order
{
ArrayList<Record> records = new ArrayList<Record>();// 保存订单上每一道的记录
Menu menu;
int table;
int yuanjia=0;//记录不打折的原价
int zhehoujia=0;//这个是打折后的价格
float acc=0;
static float panduan=1;
String orderP;//用来记录点菜的人的名字 规定是不能超过10个字符
String dianhua;//用来记录点菜人的电话 规定是11位的
int chuancai=0;//川菜
float chuanla=0;//川菜的辣度值
int chuanla_avg =-1;
int jicai=0;//晋菜
float jila=0;
int jila_avg=-1;
int zhecai=0;//浙菜
float zhela=0;
int zhela_avg =-1;
public static float panduanacc()
{
return panduan;
}
void chuancaide()
{
for(int i=0;i<records.size();i++)
{
if(records.get(i)!=null)
{
if(records.get(i).d.isT!=null)
{
if(records.get(i).d.kowei.equals("川菜"))
{
this.chuancai+=records.get(i).num;
this.chuanla+=(records.get(i).num*records.get(i).kouwei);
}
}
}
}
if(this.chuancai!=0)
{
this.chuanla_avg =Math.round(this.chuanla*1.0f/this.chuancai*1.0f);
}
}

void jicaide()
{

for(int i2=0;i2<records.size();i2++)
{
if(records.get(i2)!=null)
{
if(records.get(i2).d.isT!=null)
{
if(records.get(i2).d.kowei.equals("晋菜"))
{

// this.jicai+=records.get(i2).num;
// this.jila+=records.get(i2).num*records.get(i2).d.dudu;

this.jicai+=records.get(i2).num;
this.jila+=(records.get(i2).num*records.get(i2).kouwei);
}
}
}
}
if(this.jicai!=0)
{
this.jila_avg=Math.round(this.jila*1.0f/this.jicai*1.0f);
}
}
void zhecaide()
{
for(int i3 = 0; i3 <records.size(); i3++)
{
if(records.get(i3)!=null)
{
if(records.get(i3).d.isT!=null)
{
if(records.get(i3).d.kowei.equals("浙菜"))
{
this.zhecai+=records.get(i3).num;
this.zhela+=(records.get(i3).num*records.get(i3).kouwei);
// this.zhecai+=records.get(i3).num;
// this.zhela+=records.get(i3).num*records.get(i3).d.dudu;

}
}
}
}
if(this.zhecai!=0)
{
this.zhela_avg =Math.round(this.zhela*1.0f/this.zhecai*1.0f);

}
}
void account(String a,String b)
{//a接收日期,b接收时间
//计算星期几w
String[] s = a.split("/");
if(s[1].length()==1)
s[1]="0"+s[1];
if(s[2].length()==1)
s[2]="0"+s[2];
a = s[0]+"-"+s[1]+"-"+s[2];
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Calendar cal=Calendar.getInstance();
Date date=null;
try
{
date = format.parse(a);
} catch (ParseException e)
{
e.printStackTrace();
}
cal.setTime(date);
int w=cal.get(Calendar.DAY_OF_WEEK)-1;
if(w<=0)
w=7;
//处理时间
String[] time = b.split("/");
int h=Integer.parseInt(time[0]);
int m=Integer.parseInt(time[1]);
int sc=Integer.parseInt(time[2]);
if(w>=1&&w<=5)
{
if(h>=17&&(h<20||(h==20&&m<30)||(h==20&&m==30&&sc==0)))
acc=0.8f;
else if((h>10||(h==10&&m>=30))&&(h<14||(h==14&&m<30)||(h==14&&m==30&&sc==0)))
acc=0.6f;
else panduan=0;
}
else if((h>9||(h==9&&m>=30))&&(h<21||(h==21&&m<30)||(h==21&&m==30&&sc==0)))
acc=1;
else panduan=0;
}
int getTotalPrice()//这个函数只调用一次
{
// 计算订单的总价
int total=0;
if(records==null)
{
return 0;
}
else
{
for(int i=0;i<records.size();i++)
total+=records.get(i).getPrice();
return total;
}
}
int getZhegoujia()
{
if(records==null)
{
return 0;
}
else
{
int zhehoujia=0;
int total=0;
for(int i=0;i<records.size();i++)
{
if(acc!=1.0f)//这就判断出来这个日子是在周一到周五的
{
if(records.get(i).d.isT!=null)//说明是特色菜 这个的折扣是0.7
{
zhehoujia+=Math.round(records.get(i).getPrice()*0.7f);
// System.out.println(Math.round(records.get(i).getPrice()*0.7f));
}
else if(acc==0.8f)
{
zhehoujia+=Math.round(records.get(i).getPrice()*0.8f);
// System.out.println(Math.round(records.get(i).getPrice()*0.8f));
}
else if(acc==0.6f){
zhehoujia+=Math.round(records.get(i).getPrice()*0.6f);
// System.out.println(Math.round(records.get(i).getPrice()*0.6f));
}
}
else
{
zhehoujia+=records.get(i).getPrice();

}
}
return zhehoujia;
}
}
public Order(Menu menu,int table)
{
this.menu = menu;
this.table = table;
}
Order(){

}

//根据菜名点菜
Record addARecord(int orderNum,String dishName,int portion,int num)
{
//不用判断菜品是否存在,main里已经判断是否存在
Record r = new Record(orderNum,menu.searthDish(dishName),portion,num);
records.add(r);
return r;
}
Record addARecord(int orderNum,String dishName,int dudu,int portion,int num)
{
//不用判断菜品是否存在,main里已经判断是否存在
Record r = new Record(orderNum,menu.searthDish(dishName),dudu,portion,num);
records.add(r);
return r;
}
void delARecordByOrderNum(int orderNum)
{
//根据序号删除一条记录
for(int i=0;i<records.size();i++)
{
if(records.get(i).orderNum==orderNum)
{
records.remove(i);
return ;//删除成功
}
}
System.out.println("delete error;");//删除失败
}
}

这段代码是一个简单的餐厅点菜系统的实现。主要包括菜品类(Dish)、菜谱类(Menu)、点菜记录类(Record)和订单类(Order)。下面是对代码的简要分析:

菜品类(Dish):

用于表示菜单上的一道菜的信息,包括名称、单价、口味、特色标志等。

提供了计算菜品价格的方法。

菜谱类(Menu):

包含餐厅提供的所有菜品信息,使用ArrayList存储。

提供了添加菜品和根据菜名查找菜品的方法。

点菜记录类(Record):

保存了订单上的一道菜品记录,包括序号、菜品、份额、份数等信息。

提供了计价和获取价格的方法。

订单类(Order):

保存了用户点的所有菜的信息,包括点菜记录、菜谱、桌号、原价、折后价等信息。

包含了对特色菜口味的统计和折扣计算的方法。

具有添加记录、删除记录、计算总价和获取折后价等功能。

代码的复杂度分析和类图如下:

期中考试题目分析:

测验1-圆类设计

分数 10

全屏浏览题目

切换布局

作者 段喜龙

单位 南昌航空大学

创建一个圆形类(Circle),私有属性为圆的半径,从控制台输入圆的半径,输出圆的面积

输入格式:

输入圆的半径,取值范围为(0,+∞),输入数据非法,则程序输出Wrong Format,注意:只考虑从控制台输入数值的情况

输出格式:

输出圆的面积(保留两位小数,可以使用String.format(“%.2f”,输出数值)控制精度)

本题难度较低,故不做详细分析,将题目本身要求完成即可

import java.util.Scanner;

public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);

try {
double r = scanner.nextDouble();
if(r > 0){
Circle circle = new Circle();
circle.setCircle(r);
System.out.println(String.format("%.2f", circle.getArea()));
} else {
System.out.println("Wrong Format");
}
} catch (Exception e) {
System.out.println("Wrong Format");
}
}
}
class Circle {
private double radius;

public double setCircle(double radius) {
this.radius = radius;
return this.radius;
}



public double getArea() {
return radius*radius*Math.PI ;
}
}

复杂度分析和类图如下:

测验2-类结构设计

分数 10

全屏浏览题目

切换布局

作者 段喜龙

单位 南昌航空大学

设计一个矩形类,其属性由矩形左上角坐标点(x1,y1)及右下角坐标点(x2,y2)组成,其中,坐标点属性包括该坐标点的X轴及Y轴的坐标值(实型数),求得该矩形的面积。类设计如下图:


输入格式:

分别输入两个坐标点的坐标值x1,y1,x2,y2。

输出格式:

输出该矩形的面积值(保留两位小数)。

本题在测试用例中全部通过,但提交后缺显示未通过,存在一定问题且尚未解决

import java.util.Scanner;

public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String inputLine = sc.nextLine();
String [] inputs = inputLine.split(" ");
double[] doubleinputs = new double[inputs.length];

for (int i = 0; i < inputs.length; i++) {
doubleinputs[i] = Double.parseDouble(inputs[i]);
}

double x1=doubleinputs[0];
double y1=doubleinputs[1];
double x2=doubleinputs[2];
double y2=doubleinputs[3];

Point topLeftPoint = new Point();
topLeftPoint.setX(x1);
topLeftPoint.setY(y1);

Point lowerRightPoint = new Point();
lowerRightPoint.setX(x2);
lowerRightPoint.setY(y2);
Rectangle rectangle = new Rectangle(topLeftPoint, lowerRightPoint);
double area = rectangle.getArea();
System.out.printf ("%.2f",area);
// System.out.printf("\n");
}
}

class Point {
private double x;
private double y;

public Point() {
this.x = 0;
this.y = 0;
}

public double getX() {
return x;
}
public double getY() {
return y;
}
public void setX(double x) {
this.x = x;
}
public void setY(double y) {
this.y = y;
}
}

class Rectangle {
private Point topLeftPoint;
private Point lowerRightPoint;

public Rectangle() {
topLeftPoint = new Point();
lowerRightPoint = new Point();
}


public Point getTopLeftPoint() {
return topLeftPoint;
}
public Point getLowerRightPoint() {
return lowerRightPoint;
}
public void setTopLeftPoint(Point topLeftPoint) {
this.topLeftPoint = topLeftPoint;
}

public void setLowerRightPoint(Point lowerRightPoint) {
this.lowerRightPoint = lowerRightPoint;
}


//actually use
public Rectangle(Point x, Point y) {
this.topLeftPoint = x;
this.lowerRightPoint = y;
}
public double getHeight() {
return Math.abs(lowerRightPoint.getY() - topLeftPoint.getY());
}
public double getLength() {
return Math.abs(lowerRightPoint.getX() - topLeftPoint.getX());
}
public double getArea() {
return getHeight() * getLength();
}
}

这段代码实现了一个简单的矩形计算程序。主要包括点类(Point)、矩形类(Rectangle)和主函数入口(Main)。

点类(Point):

用于表示平面上的一个点,包括横坐标x和纵坐标y。

提供了获取和设置横纵坐标的方法。

矩形类(Rectangle):

包含了矩形的左上角和右下角两个点。

提供了设置左上角和右下角点的方法,以及计算矩形高度、长度和面积的方法。

主函数入口(Main):

使用Scanner类从控制台读取输入的字符串。

将输入字符串按空格分割成字符串数组,并转换为double型数组。

根据输入的坐标数据创建左上角和右下角点对象。

创建矩形对象,并计算矩形的面积。

使用System.out.printf方法按指定格式输出矩形的面积。

这段代码实现了一个简单的矩形计算程序,可以根据给定的坐标计算矩形的面积,并将结果输出到控制台。

测验3-继承与多态

分数 20

全屏浏览题目

切换布局

作者 段喜龙

单位 南昌航空大学

将测验1与测验2的类设计进行合并设计,抽象出Shape父类(抽象类),Circle及Rectangle作为子类,类图如下所示:


试编程完成如上类图设计,主方法源码如下(可直接拷贝使用):

public static void main(String[] args) {

// TODO Auto-generated method stub

Scanner input = new Scanner(System.in);

int choice = input.nextInt();

switch(choice) {

case 1://Circle

double radiums = input.nextDouble();

Shape circle = new Circle(radiums);

printArea(circle);

break;

case 2://Rectangle

double x1 = input.nextDouble();

double y1 = input.nextDouble();

double x2 = input.nextDouble();

double y2 = input.nextDouble();

Point leftTopPoint = new Point(x1,y1);

Point lowerRightPoint = new Point(x2,y2);

Rectangle rectangle = new Rectangle(leftTopPoint,lowerRightPoint);

printArea(rectangle);

break;

}

}

其中,printArea(Shape shape)方法为定义在Main类中的静态方法,体现程序设计的多态性。

虽然第二题的类设计通过了测试用例缺未取得分数,但该题目使用第二题的类设计却能正常通过测试点,尚不清楚原因

代码如下:

import java.util.Scanner;

abstract class Shape {
public Shape() {}
public abstract double getArea();
}

class Circle extends Shape {
private double radius = 0;

public double setCircle(double radius) {
this.radius = radius;
return this.radius;
}

public double getArea() {
return radius*radius*Math.PI ;
}

public Circle(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}

}

class Rectangle extends Shape {
private Point topLeftPoint;
private Point lowerRightPoint;
public Rectangle() {
topLeftPoint = new Point();
lowerRightPoint = new Point();
}
public Rectangle(Point topLeftPoint, Point lowerRightPoint) {
this.topLeftPoint = topLeftPoint;
this.lowerRightPoint = lowerRightPoint;
}
public double getLength() {
return Math.abs(lowerRightPoint.getX() - topLeftPoint.getX());
}
public double getHeight() {
return Math.abs(lowerRightPoint.getY() - topLeftPoint.getY());
}

public double getArea() {
return getLength() * getHeight();
}
}

class Point {
private double x;
private double y;

public Point() {
this.x = 0;
this.y = 0;
}

public double getX() {
return x;
}
public double getY() {
return y;
}
public void setX(double x) {
this.x = x;
}
public void setY(double y) {
this.y = y;
}
public Point(double x1,double y){
this.x = x;
this.y = y;
}

}


public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);

int choice = input.nextInt();

switch(choice) {
case 1://Circle
double radius = input.nextDouble();
if(radius>0){
Shape circle = new Circle(radius);
printArea(circle);
}
else
System.out.println("Wrong Format");
break;
case 2://Rectangle
double x1 = input.nextDouble();
double y1 = input.nextDouble();
double x2 = input.nextDouble();
double y2 = input.nextDouble();

Point topLeftPoint = new Point();
topLeftPoint.setX(x1);
topLeftPoint.setY(y1);

Point lowerRightPoint = new Point();
lowerRightPoint.setX(x2);
lowerRightPoint.setY(y2);

Rectangle rectangle = new Rectangle(topLeftPoint,lowerRightPoint);


printArea(rectangle);
break;
}

}

public static void printArea(Shape shape) {
System.out.printf("%.2f", shape.getArea());
}
}

这段代码实现了一个简单的图形计算程序,支持计算圆形和矩形的面积。

  1. 抽象类 Shape:
    • 作为所有图形的基类,包含一个抽象方法 getArea() 用于计算图形的面积。
  2. 圆形类 Circle:
    • 继承自 Shape 类。
    • 包含一个私有属性 radius 表示半径。
    • 提供了设置半径和获取面积的方法。
    • 重写了父类的 getArea() 方法,根据半径计算圆形的面积。
  3. 矩形类 Rectangle:
    • 继承自 Shape 类。
    • 包含两个 Point 类型的属性 topLeftPoint 和 lowerRightPoint,分别表示左上角和右下角的点。
    • 提供了获取矩形长度和高度的方法。
    • 重写了父类的 getArea() 方法,根据长度和高度计算矩形的面积。
  4. 点类 Point:
    • 表示平面上的一个点,包括横坐标 x 和纵坐标 y。
    • 提供了获取和设置横纵坐标的方法。
  5. 主函数入口 Main:
    • 使用 Scanner 类从控制台读取输入的选择。
    • 根据选择的不同,分别进行圆形和矩形的计算。
    • 如果输入的半径或坐标不合法,输出错误提示信息。
    • 调用 printArea() 方法输出计算得到的面积。

根据用户的选择计算圆形或矩形的面积,并将结果保留两位小数后输出到控制台。

该题的类设计和复杂度分析如下:

三.踩坑心得

在Java编程的过程中,我总结了一些容易出错的地方和需要注意的要点,特此分享给大家,希望能够避免类似的问题:

类名的大小写:在Java中,类名的命名需要遵循驼峰命名法,并且首字母大写,而方法和变量名则是小写开头。如果不注意大小写会导致编译错误或者运行时错误,因此在命名时一定要谨慎。

了解Java的数据类型:Java的数据类型有八种基本类型,包括byte、short、int、long、float、double、boolean和char。在进行变量声明和赋值时,需要特别注意数据类型的匹配和转换,否则会出现类型不匹配的错误,影响程序的正常运行。

掌握Java基本语法:Java有自己独特的语法规则,比如花括号、分号等等。对于这些基本语法的使用,一定要严格遵守,否则会导致编译错误或者运行时错误,影响代码的执行。

异常处理:Java中的异常处理是非常重要的,需要在代码中合理使用try-catch语句,捕获并处理异常。如果不正确地处理异常,会导致程序运行出错或者崩溃,影响系统的稳定性和可靠性。

熟练掌握Java的面向对象编程思想:作为面向对象编程语言,Java要求程序员熟练掌握面向对象编程的思想和相关知识,包括封装、继承和多态等。只有深入理解这些概念,才能更好地编写高质量的Java代码。

四.主要困难:

1.语法复杂:Java作为一种高级编程语言,其语法和概念相对复杂,初学者可能会感到难以理解。各种关键字、语法规则以及面向对象的特性需要花费较长时间去学习和消化,容易造成学习困难和理解障碍。

2.对面向对象编程的理解不够深入:Java是一种面向对象的语言,初学者可能对面向对象的思想和概念不够深入理解,导致编写的代码难以符合面向对象的要求。缺乏对封装、继承、多态等概念的深入理解,容易造成程序设计和代码实现上的困难。

3.这几次大作业尤其重视菜单_3的编码,如果菜单_3的编码完成度高且逻辑清晰的话可以省下大量编码时间并且有效降低错误出现率。

五.改进建议:

1. 重视基础知识的学习:Java编程语言本身比较复杂,想要学好Java,需要抓好基础知识的学习,如语法、变量类型、面向对象编程等基础知识。

2. 增加练习代码的编写:编写代码是学好Java的最好途径,可以选择一些经典的编程练习来提高编程能力,如LeetCode、牛客网、GitHub等。

六.总结

通过这几次题目集,我的java编码能力有了一定的增长,学到了许多库函数的使用方法,同时掌握了正则表达式的运用。另外,在java的学习过程中尤其需要重视自学,有很多内容都是需要我们自己去查阅的,不然如果所有功能都自己编写函数而不使用库函数会导致代码过长并且可靠性低。在今后的java学习中也要去多多自学并且经常练习,防止手生。另外,在多个类相互调用的情况下,要记得按照类别分类统一管理数据和方法,这能使得程序结构清晰、代码易读易维护,这一点是我此前做的不太好的。