一、前言
这次是PTA四到六次作业和期中考试的总结。
首先,第四次作业相对容易,但是也并不简单,主要有菜单计价程序-3,后面的实验五和六在他的基础上经行改进,除该题目剩下的还是比较简单,菜单计价程序-3难度主要体现在以下几个方面:
-
输入处理:需要根据规定的格式来解析输入,包括菜单、订单和代点菜信息。这需要对输入进行逐行分析,并按照不同的信息类型进行处理。
-
菜品价格计算:根据不同的份额和基础价格计算菜品的实际价格,需要考虑小数四舍五入规则。
-
订单记录管理:需要对订单中的点菜记录进行增加、删除和代点菜等操作,同时需要保证这些操作的正确性和有效性。
-
营业时间和折扣计算:需要根据营业时间和折扣规则来计算每桌的总价,包括对时间的判断和折扣的应用。
-
输出格式:输出需要按照规定的格式进行展示,要求有序号、菜名、价格等信息,并且最后输出每桌的总价。
在知识点方面,这道题主要涉及到以下内容:
-
Java类设计:需要设计菜品类、菜谱类、点菜记录类、订单类等各种类来管理不同的信息和功能,要求合理利用面向对象的设计思想。
-
字符串处理:需要对输入的字符串进行分割、匹配、提取等操作,涉及到对字符串的处理和解析。
-
条件判断和计算:需要根据不同的条件和规则进行折扣计算、价格计算等操作,要求合理运用条件判断和数学计算。
-
时间处理:需要对输入的时间信息进行解析和判断,根据时间范围来应用不同的折扣规则。
总的来说,这是一道综合性较强的程序设计题,既考察了对Java语言的熟练运用,也考察了对字符串处理、条件判断、面向对象设计等多方面知识的综合运用能力。所有写的时候也比较花时间。
然后,第五次作业的难度略有增加,就只有一道题目7-1 菜单计价程序-4,它与菜单计价程序-3相比增加了下面的难点:
-
异常情况增多:题目增加了许多异常情况的处理,如桌号时间格式非法、菜名不存在、桌号超出范围等,对于异常情况的处理更加全面。
-
特色菜的计价方法:引入了特色菜的概念,并对特色菜的折扣计价方法进行了详细说明,增加了一定的复杂性。
-
订单记录整合与合并:增加了对订单记录的整合与合并规则,避免了重复点菜记录导致的误差。
-
输出信息细化:输出信息更加具体和细化,包括每一桌的订单记录处理信息和总价信息,对程序的输出结果要求更加严格。
从难度和知识点方面来说,这道题目相对于之前的题目在异常情况处理、数据整合与合并、输出结果规范等方面有所加大,考察了我们对于异常情况处理的能力以及对订单数据处理的逻辑能力。此外,对特色菜的折扣计价方法也增加了一定的知识点难度。因此,相较于之前的题目,这道题目的难度相对更高,需要我们具备更加丰富的知识储备和逻辑分析能力。
其次,第六次作业的难度相对较高,菜单计价程序-5也是在菜单三的基础上迭代的,还是很有难度的。增加下面几个要求:
-
增加了特色菜的处理,包括口味类型和口味度值的输入。在处理口味度值时需要进行范围检查,并且在输出信息时需要按照口味类型依次输出口味度水平。
-
增加了用户订多桌菜的情况,需要在输入时增加客户的信息,并且在输出结果时需要按照字母顺序输出每位客户需要支付的金额。
-
考虑了营业时间范围以及折扣。在输出结果时需要根据时间范围计算折扣,并且对不在营业时间范围内下单的情况进行处理。
-
在计算口味度平均值时,需要考虑代点菜的情况,综合计算口味度平均值。
总体来说,菜单计价程序-5在功能上有了更多的扩展和细化,涉及到了更多的计算和逻辑判断。难度相对于菜单计价程序-3有所增加,主要体现在口味度值的处理和客户信息的管理上。知识点方面,需要涉及到类的设计和使用、输入输出格式的处理、条件判断和循环等方面的知识。要花比较多时间解决。
最后,期中考试编程题有四道题,层层递进的,不断迭代,题目难度还可以,但相对上面来说还是相对比较简单。
二、设计与分析
7-1 菜单计价程序-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+英文空格+桌号+“:”+英文空格+当前桌的总价
本次题目不考虑其他错误情况,如:桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等,在本系列的后续作业中会做要求。
输入格式:
桌号标识格式: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+英文空格+桌号+“:”+英文空格+当前桌的总价
本次题目不考虑其他错误情况,如:桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等,在本系列的后续作业中会做要求。
import java.util.*;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class Main {
public static void main(String[] args) {
Menu menu = new Menu();
date dd = new date();
Discount dc = new Discount();
Table[] ta = new Table[5];
Scanner x = new Scanner(System.in);
int portion;
int fenshu0;
int[] price = new int[10];
String dishName;
String dishnumber;
int totalPrice = 0;
int dayofweek;
int i = 0, j = 0, t = 0;
String name;
while (true) {
name = x.next();
if (name.equalsIgnoreCase("table"))
break;
if (name.equalsIgnoreCase("end"))
return;
portion = x.nextInt();
menu.add(name, portion);
}
while (true) {
t = x.nextInt();
ta[t - 1] = new Table();
String DATE = x.next();
int day = dd.getDayOfWeek(DATE);
String TIME = x.next();
ta[t - 1].discount = dc.getdiscountoftime(day, TIME);
System.out.println("table " + t + ": ");
if (t != 1)
while (true) {
name = x.next();
if (name.equalsIgnoreCase("1"))
break;
if (name.equalsIgnoreCase("end"))
return;
portion = x.nextInt();
menu.add(name, portion);
}
i = 0;
while (true) {
i++;
if (t == 1 || ((t != 1) && i != 1))
dishnumber = x.next();
else
dishnumber = String.valueOf(1);
if (dishnumber.equals("end") || dishnumber.equals("table"))
break;
int num = Integer.parseInt(dishnumber);
dishName = x.next();
if (dishName.equalsIgnoreCase("delete")) {
i--;
price[num - 1] = 0;
if (num > i)
System.out.println("delete error;");
} else {
if (dishName.equalsIgnoreCase(String.valueOf(i))) {
dishName = x.next();
portion = x.nextInt();
fenshu0 = x.nextInt();
Dish dish = menu.searchDish(menu, dishName);
if (dish == null)
System.out.println(dishName + " does not exist");
else {
price[i - 1] = dish.getPrice(portion) * fenshu0;
System.out.println(i + " table " + t + " pay for table " + dishnumber + " " + price[i - 1]);
}
} else {
portion = x.nextInt();
fenshu0 = x.nextInt();
Dish dish = menu.searchDish(menu, dishName);
if (dish == null)
System.out.println(dishName + " does not exist");
else {
price[num - 1] = dish.getPrice(portion) * fenshu0;
System.out.println(num + " " + dishName + " " + price[num - 1]);
}
}
}
}
for (i = 0; i < 10; i++) {
ta[t - 1].totalprice = ta[t - 1].totalprice + price[i];
price[i] = 0;
}
if (dishnumber.equals("end"))
break;
}
for (i = 0; i < t; i++) {
if (ta[i].discount == 11)
System.out.printf("table %d out of opening hours\n", i + 1);
else
System.out.println("table " + (i + 1) + ": " + Math.round(ta[i].totalprice * ta[i].discount / 10.0));
}
}
}
class Dish {
String name;
int unit_price;
public Dish(String name, int unit_price) {
this.name = name;
this.unit_price = unit_price;
}
public int getPrice(int portion) {
double price = 0;
if (portion == 1)
price = unit_price;
else if (portion == 2)
price = unit_price * 1.5;
else if (portion == 3)
price = unit_price * 2;
return (int) Math.round(price);
}
}
class Menu {
int i = 0;
Dish[] dishes = new Dish[10];
public void add(String dishName, int price) {
dishes[i] = new Dish(dishName, price);
i++;
}
public Dish searchDish(Menu menu, String dishName) {
for (int j = i - 1; j >= 0; j--)
if (dishes[j].name.equals(dishName))
return dishes[j];
return null;
}
}
class date {
public int getDayOfWeek(String DATE) {
String[] strings = DATE.split("/");
int[] Tentime = new int[3];
for (int i = 0; i < 3; i++)
Tentime[i] = Integer.parseInt(strings[i]);
LocalDate date1 = LocalDate.of(Tentime[0], Tentime[1], Tentime[2]);
return (date1.getDayOfWeek().getValue());
}
}
class Discount {
public int getdiscountoftime(int ddd, String time) {
int tentime;
int[] Tentime = new int[3];
String[] strings = time.split("/");
for (int i = 0; i < 3; i++)
Tentime[i] = Integer.parseInt(strings[i]);
tentime = Tentime[0] * 3600 + Tentime[1] * 60 + Tentime[2];
if ((tentime >= 10.5 * 3600 && tentime <= 14.5 * 3600) && (ddd >= 1 && ddd <= 5))
return 6;
else if ((tentime >= 17 * 3600 && tentime <= 20.5 * 3600) && (ddd >= 1 && ddd <= 5))
return 8;
else if ((tentime >= 9.5 * 3600 && tentime <= 21.5 * 3600) && (ddd == 6 || ddd == 7))
return 10;
else
return 11;
}
}
class Table {
int discount;
int totalprice;
}
类图如下:

代码难易程度如下图所示:

分析:
在写这个题目时,周末的情况总是过不去,检查了好几遍还是没能够改出来。在写该代码,主要的难点如下:
-
类之间的关系:代码中涉及了多个类之间的交互和依赖关系,比如Menu类与Dish类的关系、Discount类与Table类的关系等。理解各个类之间的作用和关联是理解整个程序的前提。
-
输入输出处理:代码中使用了Scanner类来进行输入,同时也有一些比较复杂的条件判断来处理不同的输入情况,比如根据输入的指令来执行不同的操作。这需要对输入输出流以及条件判断有一定的了解和掌握。
-
时间和日期处理:程序涉及了对日期和时间的处理,包括使用Java 8中的LocalDate类和时间格式化等操作。这部分涉及了一些时间和日期的计算和转换知识。
-
数组和循环处理:代码中使用了数组来存储菜品信息和桌子信息,并通过循环来处理输入的菜品和计算总价等操作。对数组的使用和循环逻辑的理解是必不可少的。
搞定这几点写该题就没什么问题了。
7-1 菜单计价程序-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)//根据序号查找一条记录
}
本次课题比菜单计价系列-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+英文空格+桌号+“:”+英文空格+当前桌的原始总价+英文空格+当前桌的计算折扣后总价
我的代码如下:
import java.util.*;
public class Main {
public static void main(String[] args) {
try (Scanner in = new Scanner(System.in)) {
String[] a=new String[50];
int[]b=new int[50];
Menu c=new Menu();
table[] t=new table[50];
Dish g=new Dish();
int i=0;//桌号
int j=0;//菜数
int p=0;//当前处理桌号
int lastdish=0;
int dc1=0,dc2=0,dc3=0,dd1=0,dd2=0,dd3=0,dd4=0;
int inputnum=0,h;
a[0]=in.nextLine();
b[0]=0;
while(!a[inputnum].equals("end"))
{
inputnum++;
a[inputnum]=in.nextLine();
b[inputnum]=0;
if(a[inputnum].isEmpty()) {
System.out.println("wrong format");
inputnum--;
}
}
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.println("record serial number sequence error");
}
else
{
t[p].selforder.addARecord(0,dc1,arr[1],dc2,dc3,true);
g=c.searthDish(arr[1]);
if(g!=null&&t[p].flag)
{
if(dc2>3&&dc2<10||dc2<=0&&dc2>-10)//情况9
{
//序号+" portion out of range "+份额
System.out.println(dc1+" portion out of range "+dc2);
}
else if(dc3>15)
{
System.out.println(dc1+" num out of range "+dc3);
}
else
{
t[p].selforder.records[t[p].k].d=g;
//System.out.println(t[p].selforder.records[]);
int x=t[p].selforder.records[t[p].k].getPrice();
//2 油淋生菜 27
lastdish=dc1;
System.out.println(dc1+" "+arr[1]+" "+x);
}
}
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();
}
}
}
class Dish
{
String name="";//菜品名称
int unit_price;
boolean special=false;//特色菜,true为是
//单价
int getPrice(int portion)
{
int 菜价=0;
//单菜价格
switch(portion)
{
case 1: 菜价=unit_price;break;
case 2: 菜价=(int)Math.ceil(1.0*unit_price*3/2);break;
case 3: 菜价=unit_price*2;break;
}
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 orderNum=0;//序号\
int portion=0;
int num=0;//份数
int tablenum=0;//桌号//没什么用
boolean self=true;
//份额(1/2/3代表小/中/大份)
int getPrice()
{
int n=0;
n=num*d.getPrice(portion);
//2 油淋生菜 27
// System.out.println(n);
return n;
}//计价,计算本条记录的价格
}
class Order
{
Record[] records=new Record[20];
int j=0;
int[] deletenum=new int[50];
//添加一条菜品信息到订单中。
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].orderNum=orderNum;
records[j].d.name=dishName;
records[j].portion=portion;
records[j].num=num;
records[j].self=self;
//System.out.println(num);
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;
}
//records[orderNum-1].getPrice();
}
}
else//情况4
{
System.out.println("deduplication "+orderNum);
}
}
void srarchrecord(Record g,int k)
{
for(int i=0;i<k;i++)
{
if(g.d.name.equals(records[i].d.name)&&g.portion==records[i].portion&&records[i].self==true)
{
records[i].num+=g.num;
g.num=0;
break;
}
}
}
}
class table
{
int tablenum;//桌号
String time;//点菜时间//2023/3/22 12/2/3
int year=0,month=0,day=0,ww=0,hh=0,mm=0,ss=0;
boolean flag=false;//判断时间是否正确
double count=0;//普通菜折扣
double specialcount=1;
Order selforder=new Order();//本桌订单
int sum=0;//计算总价
int truesum=0;//未打折价
int k=0;//点菜次数
int sumdish=0;//菜总数
void input(String time,int b)//预处理
{
String[] arr1=time.split(" ");
int blank=0;
for(int bk=0;bk<time.length();bk++)
{
if(time.charAt(bk)==' ')
{
blank++;
}
}
//桌号
if(blank!=3||!arr1[1].matches("^[1-9][0-9]{0,}$")||arr1.length!=4)
{
System.out.println("wrong format");
}
//System.out.println();
else
{
this.time=arr1[2]+" "+arr1[3];
// System.out.println();
tablenum=Integer.parseInt(arr1[1]);
if(tablenum<=55&&tablenum>=1)
{
if(this.time.matches("^([0-9]{4}/[0-9]{1,2}/[0-9]{1,2}) ([0-9]{1,2}/[0-9]{1,2}/[0-9]{1,2})$"))
{
if(arr1[2].matches("^(([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)$")&&arr1[3].matches("^([0-9]|([01][0-9])|(2[0-3]))/([0-9]|([0-5][0-9]))/([0-9]|([0-5][0-9]))$"))
{
boolean flag1=judgetime1();
if(flag1==true)//时间有效
{
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()//是否有效//使用正则表达式
{
String[] arr=time.split(" ");
boolean flag=arr[0].matches("^(2022|2023)/(([13578]|0[13578]|10|12)/(([1-9]|0[1-9])|([12][0-9])|3[01])|([469]|0[469]|11)/(([1-9]|0[1-9])|([12][0-9])|30)|(2|02)/(([1-9]|0[1-9])|(1[0-9])|(2[0-8])))$");
boolean flag1=arr[1].matches("^([0-9]|([01][0-9])|(2[0-3]))/([0-9]|([0-5][0-9]))/([0-9]|([0-5][0-9]))$");
return (flag&&flag1);
}
void getTotalPrice()//计算桌总价
{
if(flag)
{
int j=selforder.j;
for(int i=j-1;i>=0;i--)
{
selforder.srarchrecord(selforder.records[i],i);
}
for(int i=0;i<j;i++)
{
int x=0;
x=selforder.records[i].getPrice();
truesum+=x;
if(selforder.records[i].d.special==true)//特色菜
{
sum+=(int)(x*specialcount+0.5);
}
else
sum+=(int)(x*count+0.5);
}
System.out.println("table "+tablenum+": "+truesum+" "+sum);
//table 1: 63
}
}
void jscount()//运用时间计算折扣
{
if(ww>=1&&ww<=5)
{
specialcount=0.7;
if(hh>=17&&hh<20)
count=0.8;
else if(hh==20&&mm<30)
count=0.8;
else if(hh==20&&mm==30&&ss==0)
count=0.8;
else if(hh>=11&&hh<=13||hh==10&&mm>=30)
count=0.6;
else if(hh==14&&mm<30)
count=0.6;
else if(hh==14&&mm==30&&ss==0)
count=0.6;
}
else
{
specialcount=1;
if(hh>=10&&hh<=20)
count=1.0;
else if(hh==9&&mm>=30)
count=1.0;
else if(hh==21&&mm<30||hh==21&&mm==30&&ss==0)
count=1.0;
}
}
void pdflag()//判断时间是否正确
{
if(count==0)
{
System.out.println("table "+tablenum+" out of opening hours");
flag=false;
}
else
flag=true;
}
void timechange()//时间转换
{
//2023/3/22 12/2/3
String[] arr=time.split(" ");
String[] arr1=arr[0].split("/");
String[] arr2=arr[1].split("/");
year=Integer.parseInt(arr1[0]);//时间
month=Integer.parseInt(arr1[1]);
day=Integer.parseInt(arr1[2]);
Calendar c = Calendar.getInstance();
c.set(year,month-1,day);//设置时间
ww=c.get(Calendar.DAY_OF_WEEK);
hh=Integer.parseInt(arr2[0]);//时间
mm=Integer.parseInt(arr2[1]);
ss=Integer.parseInt(arr2[2]);
if(ww==1)
ww=7;
else
ww--;
}
boolean searthtable(table[]t,int num,int p)
{
for(int i=0;i<50;i++)
{
if(t[i]!=null&&i!=p)
{
if(t[i].tablenum==num&&t[i].flag)
return true;
}
else
break;
}
//"Table number :"+被点菜桌号+" does not exist"
System.out.println("Table number :"+num+" does not exist");
return false;
}
int searchtime(table[]t,table a,int sumtable)//若找到返回对应桌,找不到返回下一个空桌
{
//(时段的认定:周一到周五的中午或晚上是同一时段,或者周末时间间隔1小时(不含一小时整,精确到秒)
for(int i=0;i<sumtable;i++)
{
if(a.tablenum==t[i].tablenum)
if(a.year==t[i].year)
{
if(a.day==t[i].day)
{
if(a.ww>=1&&a.ww<=5)//周1~5
{
if(a.hh<=14&&t[i].hh<=14||a.hh>14&&t[i].hh>14)//在同一时段
{
return i;
}
}
else//周末
{
if(Math.abs((a.hh-t[i].hh)*60*60+(a.mm-t[i].mm)*60)+(a.ss-t[i].ss)<60*60)//在同一时段
{
return i;
}
}
}
}
}
//System.out.println(sumtable);
return sumtable;
}
}
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;
//麻婆豆腐 12
if(arr.length>5)
{
b[i]=1;
}
if(a[i].matches("^[\u4e00-\u9fa5]{1,} ([1-9][0-9]{0,2})$")==true)//普通菜存入
{
flag=true;
}
//油淋生菜 9 T
else if(a[i].matches("^[\u4e00-\u9fa5]{1,4} ([1-9][0-9]{0,2}) [T]$")==true)//特色菜存入
{
flag=true;
}
//table 31 2023/2/1 14/20/00
else if(arr[0].equals("table")==true)//桌
{
int blank=0;
for(int bk=0;bk<a[i].length();bk++)
{
if(a[i].charAt(bk)==' ')
{
blank++;
}
}
if(arr[1].matches("^([1-9][0-9]{0,})$")&&blank==3)
flag=true;
//int blank=0;
}
//1 麻婆豆腐 1 16
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;
}
//1 1 麻婆豆腐 1 16
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;
}
//2 delete
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;
}
}
}
}
类图如下:

代码难度如下:

分析:
在写这道题目的时候遇到了下面几个难点:
-
逻辑复杂性: 考虑到需要处理菜单记录、订单记录、删除记录、代点菜信息,以及不同桌号的订单计算等,代码的逻辑结构可能会变得非常复杂。
-
口味度计算: 除了普通菜品的价格计算外,还需要考虑特色菜的口味度计算,并且要累计本桌各类菜系所有记录的口味度总和,再进行平均值计算。
-
客户信息管理: 需要按字母顺序输出每位客户需要支付的金额,这可能需要对客户信息进行合理的数据结构设计和排序算法。
-
输入格式处理: 输入的格式较为复杂,需要编写相应的输入解析代码来提取有效信息,同时进行格式验证和错误处理。
-
折扣策略: 需要根据不同的时间段和菜品类型计算折扣,这也对代码的逻辑和计算提出了更高的要求。
只要解决这几个方面的问题,该道题目就没什么问题,我最后遇到的问题是对输入格式的判断有问题,但是只要仔细分析还是可以解决该问题。
7-1 菜单计价程序-5
本题在菜单计价程序-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+英文空格+桌号+“:”+英文空格+当前桌的计算折扣后总价+英文空格+辣度平均值+英文空格+酸度平均值+英文空格+甜度平均值+英文空格
最后按拼音顺序输出每位客户(不考虑客户同名或拼音相同的情况)的支付金额,格式: 用户姓名+英文空格+手机号+英文空格+支付总金额,按输入顺序排列。
代码如下
import java.util.*;
import java.util.Scanner;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.time.LocalDate;
import java.util.ArrayList;
class Dish{
String name;
int unit_price;
int getPrice(int portion) {
float n[] = {1, 1.5f, 2};
return Math.round((unit_price * n[portion - 1]));
}//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份)
}
class SpecialDish extends Dish{
String taste;
}
class Menu{
Dish[] dishes = new Dish[10];//菜品数组,保存所有菜品信息
SpecialDish[] specialDishes;
int dishNum1;
int dishNum2;
public SpecialDish searthSpecialDish(String dishName){
for(int i = 0; i < dishNum1; i++) {
if(dishName.equals(specialDishes[i].name)){
return specialDishes[i];
}
}
return null;
}
public Dish searthDish(String dishName){
for(int i = 0; i < dishNum2; i++) {
if(dishName.equals(dishes[i].name)){
return dishes[i];
}
}
return null;
}
public SpecialDish addSpecialDish(String dishName,int unit_price,String taste){
SpecialDish addDish=new SpecialDish();
addDish.name=dishName;
addDish.unit_price=unit_price;
addDish.taste=taste;
return addDish;
}
public Dish addDish(String dishName,int unit_price){
Dish addDish=new Dish();
addDish.name=dishName;
addDish.unit_price=unit_price;
return addDish;
}
}
class Record{
int orderNum;//序号
Dish d;//菜品
int taste = -1;//口味度
int portion;//份额(1/2/3代表小/中/大份)
int num;//数量
int spicy;
int acidity;
int sweetness;
boolean isSpecialDish;
public int getPrice() {
return d.getPrice(portion)*num;
}
}
class Order {
int dishNum;
int allCommonPrice;
int allSpecialPrice;
Record[] records;
public void addPortion() {
for(int k = 0;k < dishNum-1;k++){
for(int l = k+1;l<dishNum;l++){
if(records[k].d.name.equals(records[l].d.name)&&records[k].portion == records[l].portion){
records[k].num+=records[l].num;
records[l].num = 0;
}
}
}
}
public void getTotalPrice(){
for(int k=0;k<dishNum;k++) {
if(!records[k].isSpecialDish)
allCommonPrice+=records[k].getPrice();
else
allSpecialPrice+=records[k].getPrice();
}
}
public int getTotalPrice(double commonDiscount,double specialDiscount){
int all = 0;
for(int k=0;k<dishNum;k++) {
if(!records[k].isSpecialDish)
all+=Math.round(records[k].getPrice()*commonDiscount);
else
all+=Math.round(records[k].getPrice()*specialDiscount);
}
return all;
}
public Record addARecord(int orderNum,String dishName,int portion,int num , Menu menu){
Record x=new Record();
x.d=menu.searthDish(dishName);
x.orderNum=orderNum;
x.portion=portion;
x.num=num;
return x;
}
public Record addASpecialRecord(int orderNum,String dishName,int portion,int num ,Menu menu,int tasteNum , boolean forOther){
Record x=new Record();
x.d=menu.searthSpecialDish(dishName);
x.orderNum=orderNum;
x.portion=portion;
x.num=num;
if(!forOther){
if(menu.searthSpecialDish(dishName).taste.equals("川菜")){
x.spicy = tasteNum;
x.acidity = -1;
x.sweetness = -1;
}
if(menu.searthSpecialDish(dishName).taste.equals("晋菜")){
x.spicy = -1;
x.acidity = tasteNum;
x.sweetness = -1;
}
if(menu.searthSpecialDish(dishName).taste.equals("浙菜")){
x.spicy = -1;
x.acidity = -1;
x.sweetness = tasteNum;
}
}
else{
x.spicy = -1;
x.acidity = -1;
x.sweetness = -1;
}
return x;
}
public int findRecordByNum(int orderNum){
for(int i = 0; i<dishNum;i++) {
if(records[i].orderNum==orderNum) {
return 1;
}
}
return 0;
}
public void delARecordByOrderNum(int orderNum){
for(int i=0;i<dishNum;i++) {
if(orderNum==records[i].orderNum) {
records[i].num=0;
}
}
}
}
class Table{
int tableNum;
String tableName;
String telephoneNum;
String mainTime;
String remainTime;
Order order;
double commonDiscount;
double specialDiscount;
int averageSpicy;
int averageAcidity;
int averageSweetness;
double spicyNum;
double acidityNum;
double sweetnessNum;
public boolean timeJudgement1(){
String[] x = remainTime.split("/");
String[] y = mainTime.split("/");
int year = Integer.parseInt(y[0]);
int month = Integer.parseInt(y[1]);
int day = Integer.parseInt(y[2]);
double hour = Double.parseDouble(x[0]);
double minute = Double.parseDouble(x[1]);
double second = Double.parseDouble(x[2]);
LocalDate date = LocalDate.of(year,month,day);
int weekOfDay = date.getDayOfWeek().getValue();
if (weekOfDay == 6 || weekOfDay == 7) {
if (hour >= 10 && hour < 21 || hour == 9 && minute >= 30 || hour == 21 && minute < 30 ||hour == 21 && minute == 30 && second == 0) {
specialDiscount = commonDiscount = 1;
return true;
}
else {
return false;
}
}
if (weekOfDay >= 1 && weekOfDay <= 5) {
if (hour > 17 && hour < 20 || hour == 17 && minute >= 0 || hour == 20 && minute < 30 || hour == 20 && minute == 30 && second == 0) {
commonDiscount = 0.8;
specialDiscount = 0.7;
return true;
}
else if (hour > 10 && hour < 14 || hour == 10 && minute >= 30 || hour == 14 && minute < 30 || hour == 14 && minute == 30 && second == 0) {
commonDiscount = 0.6;
specialDiscount = 0.7;
return true;
}
else {
return false;
}
}
return false;
}
public int tablePrice(){
return this.order.getTotalPrice(commonDiscount,specialDiscount);
}
public void getTaste(){
for(int k = 0;k<this.order.dishNum;k++){
if(order.records[k].isSpecialDish){
if(order.records[k].spicy!=-1){
averageSpicy+=order.records[k].spicy*order.records[k].num;
spicyNum=order.records[k].num+spicyNum;
}
if(order.records[k].acidity!=-1){
averageAcidity+=order.records[k].acidity*order.records[k].num;
acidityNum=order.records[k].num+acidityNum;
}
if(order.records[k].sweetness!=-1){
averageSweetness+=order.records[k].sweetness*order.records[k].num;
sweetnessNum=order.records[k].num+sweetnessNum;
}
}
}
if(spicyNum!=0){
averageSpicy=(int)Math.round(averageSpicy/spicyNum);
}
if(acidityNum!=0){
averageAcidity=(int)Math.round(averageAcidity/acidityNum);
}
if(sweetnessNum!=0){
averageSweetness=(int)Math.round(averageSweetness/sweetnessNum);
}
}
public String spicyLevel(){
if(averageSpicy==0)
return "不辣";
if(averageSpicy==1)
return "微辣";
if(averageSpicy==2)
return "稍辣";
if(averageSpicy==3)
return "辣";
if(averageSpicy==4)
return "很辣";
if(averageSpicy==5)
return "爆辣";
return null;
}
public String acidityLevel(){
if(averageAcidity==0)
return "不酸";
if(averageAcidity==1)
return "微酸";
if(averageAcidity==2)
return "稍酸";
if(averageAcidity==3)
return "酸";
if(averageAcidity==4)
return "很酸";
return null;
}
public String sweetnessLevel(){
if(averageSweetness==0)
return "不甜";
if(averageSweetness==1)
return "微甜";
if(averageSweetness==2)
return "稍甜";
if(averageSweetness==3)
return "甜";
return null;
}
public void giveTaste(String name , int num , int tasteLevel , Menu menu){
if(menu.searthSpecialDish(name).taste.equals("川菜")){
averageSpicy+=tasteLevel*num;
spicyNum+=num;
}
if(menu.searthSpecialDish(name).taste.equals("晋菜")){
averageAcidity+=tasteLevel*num;
acidityNum+=num;
}
if(menu.searthSpecialDish(name).taste.equals("浙菜")){
averageSweetness+=tasteLevel*num;
sweetnessNum+=num;
}
}
}
class lastPrint{
ArrayList<Table> tables = new ArrayList<>();
PersonPay[] personPays;
int p;
public void print(){
for (Table table : tables) {
table.order.getTotalPrice();
table.getTaste();
if(table.spicyNum==0&&table.acidityNum==0&&table.sweetnessNum==0)
System.out.println("table " + table.tableNum + ": " + (table.order.allCommonPrice + table.order.allSpecialPrice) + " " + table.tablePrice()+" ");
if(table.spicyNum!=0&&table.acidityNum==0&&table.sweetnessNum==0)
System.out.println("table " + table.tableNum + ": " + (table.order.allCommonPrice + table.order.allSpecialPrice) + " " + table.tablePrice() + " 川菜 " +(int)table.spicyNum+" "+table.spicyLevel());
if(table.spicyNum==0&&table.acidityNum!=0&&table.sweetnessNum==0)
System.out.println("table " + table.tableNum + ": " + (table.order.allCommonPrice + table.order.allSpecialPrice) + " " + table.tablePrice() + " 晋菜 " +(int)table.acidityNum+" "+table.acidityLevel());
if(table.spicyNum==0&&table.acidityNum==0&&table.sweetnessNum!=0)
System.out.println("table " + table.tableNum + ": " + (table.order.allCommonPrice + table.order.allSpecialPrice) + " " + table.tablePrice() + " 浙菜 " +(int)table.sweetnessNum+" "+table.sweetnessLevel());
if(table.spicyNum!=0&&table.acidityNum!=0&&table.sweetnessNum==0)
System.out.println("table " + table.tableNum + ": " + (table.order.allCommonPrice + table.order.allSpecialPrice) + " " + table.tablePrice() + " 川菜 " +(int)table.spicyNum+" "+table.spicyLevel()+" 晋菜 "+(int)table.acidityNum+" "+table.acidityLevel());
if(table.spicyNum!=0&&table.acidityNum==0&&table.sweetnessNum!=0)
System.out.println("table " + table.tableNum + ": " + (table.order.allCommonPrice + table.order.allSpecialPrice) + " " + table.tablePrice() + " 川菜 " +(int)table.spicyNum+" "+table.spicyLevel()+" 浙菜 "+(int)table.sweetnessNum+" "+table.sweetnessLevel());
if(table.spicyNum==0&&table.acidityNum!=0&&table.sweetnessNum!=0)
System.out.println("table " + table.tableNum + ": " + (table.order.allCommonPrice + table.order.allSpecialPrice) + " " + table.tablePrice() + " 晋菜 " +(int)table.acidityNum+" "+table.acidityLevel()+" 浙菜 "+(int)table.sweetnessNum+" "+table.sweetnessLevel());
if(table.spicyNum!=0&&table.acidityNum!=0&&table.sweetnessNum!=0)
System.out.println("table " + table.tableNum + ": " + (table.order.allCommonPrice + table.order.allSpecialPrice) + " " + table.tablePrice() + " 川菜 " +(int)table.spicyNum+" "+table.spicyLevel()+" 晋菜 "+(int)table.acidityNum+" "+table.acidityLevel()+" 浙菜 "+(int)table.sweetnessNum+" "+table.sweetnessLevel());
}
}
public void payPrint(){
for(int k=0;k<p;k++){
for(Table table:tables){
if(table.tableName.equals(personPays[k].name)){
personPays[k].payPrice+=table.tablePrice();
}
}
}
for(int k=0;k<p-1;k++){
for(int l=k+1;l<p;l++){
if(personPays[k].name.toLowerCase().compareTo(personPays[l].name.toLowerCase())>0) {
PersonPay x;
x=personPays[l];
personPays[l]=personPays[k];
personPays[k]=x;
}
}
}
for(int k=0;k<p;k++){
System.out.println(personPays[k].name+" "+personPays[k].telephoneNum+" "+personPays[k].payPrice);
}
}
}
class PersonPay{
String name;
String telephoneNum;
int payPrice;
}
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
Dish[] dishes = new Dish[20];
SpecialDish[] specialDishes = new SpecialDish[20];
ArrayList<Table> tables = new ArrayList<>();
Table table = new Table();
Record[] records = new Record[20];
PersonPay[] personPays = new PersonPay[10];
Order order = new Order();
Menu menu = new Menu();
lastPrint print = new lastPrint();
int x = 0 , y = 0 , z = 0 , z1 = 0 , p = 0 , tableNum , dishNum , portion , num , unit_price , deleteNum , tasteNum;
String menuName , dayTime , hourTime , name , tableName , telephoneNum , taste;
boolean isHaveTable = false , forOther = false;
for(;;){
String input = in.readLine();
if(input.equals("end")){
if(x!=0){
table.order = order;
tables.add(x-1 , table);
}
print.tables = tables;
print.personPays = personPays;
print.print();
print.payPrint();
break;
}
String[] getInput = input.split(" ");
if(input.matches("^(table)( )([1-9][0-9]*)( )(:)( )(\\S+)( )((136|133|135|180|181|189)[0-9]{8})( )([0-9]{4})(/)([0-9]|[0-9]{2})(/)([0-9]|[0-9]{2})( )([0-9]|[0-9]{2})(/)([0-9]|[0-9]{2})(/)([0-9]|[0-9]{2})$")) {
if(x != 0) {
table.order = order;
tables.add(x-1 , table);
table = new Table();
y = 0;
}
isHaveTable = true;
tableNum = Integer.parseInt(getInput[1]);
tableName = getInput[3];
telephoneNum = getInput[4];
dayTime = getInput[5];
hourTime = getInput[6];
table.tableNum = tableNum;
table.tableName = tableName;
table.telephoneNum = telephoneNum;
table.mainTime = dayTime;
table.remainTime = hourTime;
if(!table.timeJudgement1()){
isHaveTable = false;
System.out.println("table " +table.tableNum + " out of opening hours");
continue;
}
order = new Order();
records = new Record[10];
if(x==0){
personPays[p] = new PersonPay();
personPays[p].name = tableName;
personPays[p].telephoneNum = telephoneNum;
p++;
print.p = p;
}
else{
for(int i=0;i<p;i++){
if(personPays[i].name.equals(tableName)&&personPays[i].telephoneNum.equals(telephoneNum))
break;
if(i==p-1){
personPays[p] = new PersonPay();
personPays[p].name = tableName;
personPays[p].telephoneNum = telephoneNum;
p++;
print.p = p;
}
}
}
System.out.println("table "+tableNum+": ");
x++;
}
else if(input.matches("^(\\S+)( )([1-9][0-9]*)$")){
int i = 0;
menuName = getInput[0];
unit_price = Integer.parseInt(getInput[1]);
if(z == 0) {
dishes[0] = menu.addDish(menuName , unit_price);
z++;
}
else{
for(;i < z ; i++) {
if(menuName.equalsIgnoreCase(dishes[i].name)) {
dishes[i].unit_price = unit_price;
break;
}
}
}
if(i == z){
dishes[z] = menu.addDish(menuName , unit_price);
z++;
}
menu.dishes = dishes;
menu.dishNum = z;
}
else if(input.matches("^(\\S+)( )(\\S+)( )([1-9][0-9]*)( )(T)$")){
int i = 0;
menuName = getInput[0];
taste = getInput[1];
unit_price = Integer.parseInt(getInput[2]);
if(z1 == 0) {
specialDishes[0] = menu.addSpecialDish(menuName , unit_price , taste);
z1++;
}
else{
for(;i < z1 ; i++) {
if(menuName.equalsIgnoreCase(specialDishes[i].name)) {
specialDishes[i].unit_price = unit_price;
break;
}
}
}
if(i == z1){
specialDishes[z1] = menu.addSpecialDish(menuName , unit_price , taste);
z1++;
}
menu.specialDishes = specialDishes;
menu.dishNum1 = z1;
}
else if(input.matches("^([1-9][0-9]*)( )(\\S+)( )([1-9][0-9]*)( )([1-9][0-9]*)$")){
if(!isHaveTable)
continue;
dishNum = Integer.parseInt(getInput[0]);
name = getInput[1];
portion = Integer.parseInt(getInput[2]);
num = Integer.parseInt(getInput[3]);
if(menu.searthDish(name) != null) {
records[y] = new Record();
records[y] = order.addARecord(dishNum , name , portion , num , menu);
records[y].isSpecialDish = false;
System.out.println(records[y].orderNum+" "+records[y].d.name+" "+records[y].getPrice());
y++;
order.records = records;
order.dishNum = y;
}
else{
System.out.println(name+" does not exist");
}
}
else if(input.matches("^([1-9][0-9]*)( )(\\S+)( )([0-9]+)( )([1-9][0-9]*)( )([1-9][0-9]*)$")){
if(!isHaveTable)
continue;
dishNum = Integer.parseInt(getInput[0]);
name = getInput[1];
tasteNum = Integer.parseInt(getInput[2]);
portion = Integer.parseInt(getInput[3]);
num = Integer.parseInt(getInput[4]);
if(menu.searthSpecialDish(name) != null) {
if(((menu.searthSpecialDish(name).taste.equals("川菜") && tasteNum >= 0 && tasteNum <= 5) || (menu.searthSpecialDish(name).taste.equals("晋菜") && tasteNum>=0 && tasteNum <= 4) || (menu.searthSpecialDish(name).taste.equals("浙菜") && tasteNum>=0 && tasteNum <= 3))){
records[y] = new Record();
records[y] = order.addASpecialRecord(dishNum , name , portion , num , menu , tasteNum , forOther);
records[y].isSpecialDish = true;
System.out.println(records[y].orderNum+" "+records[y].d.name+" "+records[y].getPrice());
y++;
order.records = records;
order.dishNum = y;
}
}
else{
System.out.println(name+" does not exist");
continue;
}
if(menu.searthSpecialDish(name).taste.equals("川菜")){
if(tasteNum<0||tasteNum>5)
System.out.println("spicy num out of range :"+tasteNum);
}
if(menu.searthSpecialDish(name).taste.equals("晋菜")){
if(tasteNum<0||tasteNum>4)
System.out.println("acidity num out of range :"+tasteNum);
}
if(menu.searthSpecialDish(name).taste.equals("浙菜")){
if(tasteNum<0||tasteNum>3)
System.out.println("sweetness num out of range :"+tasteNum);
}
}
else if(input.matches("([1-9][0-9]*)( )(delete)")) {
if(!isHaveTable)
continue;
deleteNum = Integer.parseInt(getInput[0]);
if(order.findRecordByNum(deleteNum) == 1){
order.delARecordByOrderNum(deleteNum);
}
else
System.out.println("delete error;");
}
else if(input.matches("^([1-9][0-9]*)( )([1-9][0-9]*)( )(\\S+)( )([1-9][0-9]*)( )([1-9][0-9]*)$")) {
if(!isHaveTable)
continue;
int t = Integer.parseInt(getInput[0]);
dishNum = Integer.parseInt(getInput[1]);
name = getInput[2];
portion = Integer.parseInt(getInput[3]);
num = Integer.parseInt(getInput[4]);
for(int i = 0;i<x-1;i++){
if(tables.get(i).tableNum == t){
if(menu.searthDish(name) != null) {
records[y] = new Record();
records[y] = order.addARecord(dishNum , name , portion , num , menu);
records[y].isSpecialDish = false;
System.out.println(dishNum+" table "+table.tableNum+" pay for table "+t+" "+records[y].getPrice());
y++;
order.records = records;
order.dishNum = y;
}
break;
}
}
}
else if(input.matches("^([1-9][0-9]*)( )([1-9][0-9]*)( )(\\S+)( )([0-9]*)( )([1-9][0-9]*)( )([1-9][0-9]*)$")) {
if(!isHaveTable)
continue;
int t = Integer.parseInt(getInput[0]);
dishNum = Integer.parseInt(getInput[1]);
name = getInput[2];
tasteNum = Integer.parseInt(getInput[3]);
portion = Integer.parseInt(getInput[4]);
num = Integer.parseInt(getInput[5]);
for(int i = 0;i<x-1;i++){
if(tables.get(i).tableNum == t){
if(menu.searthSpecialDish(name) != null) {
if(((menu.searthSpecialDish(name).taste.equals("川菜") && tasteNum >= 1 && tasteNum <= 5) || (menu.searthSpecialDish(name).taste.equals("晋菜") && tasteNum <= 4) || (menu.searthSpecialDish(name).taste.equals("浙菜") && tasteNum <= 3))){
records[y] = new Record();
records[y] = order.addASpecialRecord(dishNum , name , portion , num , menu , tasteNum , !forOther);
records[y].isSpecialDish = true;
System.out.println(dishNum+" table "+table.tableNum+" pay for table "+t+" "+records[y].getPrice());
tables.get(i).giveTaste(name,num,tasteNum,menu);
y++;
order.records = records;
order.dishNum = y;
}
}
break;
}
}
}
else {
System.out.println("wrong format");
}
}
}
}
类图如下:

代码难度如下:

分析
这个题目比较复杂要考虑到多方面问题,最大的问题在于设计合理的类结构和方法,并正确处理各种输入情况的逻辑。另外,对于口味度的计算和折扣的处理也是需要细致思考和严谨编码的部分。建议可以先从整体上构思程序的结构和各个类的关系,然后逐步实现每个类的功能,测试每一步的结果,确保逻辑的准确性和稳定性。同时,针对口味度和折扣的计算逻辑,需要仔细思考和验证,确保其正确性。所以写这个题目比较麻烦,需要有耐心。
期中考试
7-1 测验1-圆类设计
创建一个圆形类(Circle),私有属性为圆的半径,从控制台输入圆的半径,输出圆的面积
输入格式:
输入圆的半径,取值范围为(0,+∞),输入数据非法,则程序输出Wrong Format,注意:只考虑从控制台输入数值的情况
输出格式:
输出圆的面积(保留两位小数,可以使用String.format(“%.2f”,输出数值)控制精度)
代码如下
import java.util.*;
public class Main{
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
double radius = scanner.nextDouble();
if (radius <= 0) {
System.out.println("Wrong Format");
} else {
Circle circle = new Circle(radius);
System.out.println(String.format("%.2f", circle.area()));
}
}
}
class Circle {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double area() {
return Math.PI * radius * radius;
}
}
该题目比较简单就不进行分析
7-2 测验2-类结构设计
设计一个矩形类,其属性由矩形左上角坐标点(x1,y1)及右下角坐标点(x2,y2)组成,其中,坐标点属性包括该坐标点的X轴及Y轴的坐标值(实型数),求得该矩形的面积。类设计如下图:

输入格式:
分别输入两个坐标点的坐标值x1,y1,x2,y2。
输出格式:
输出该矩形的面积值(保留两位小数)。
代码如下:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
double x1 = in.nextDouble();
double y1 = in.nextDouble();
double x2 = in.nextDouble();
double y2 = in.nextDouble();
Point point1 = new Point(x1, y1);
Point point2 = new Point(x2, y2);
Rectangle rectangle = new Rectangle(point1, point2);
System.out.printf("%.2f", rectangle.getArea());
}
}
class Rectangle {
private Point topLeftPoint;
private Point lowerRightPoint;
public Rectangle(Point topLeftPoint, Point lowerRightPoint) {
this.topLeftPoint = topLeftPoint;
this.lowerRightPoint = lowerRightPoint;
}
public double getArea() {
double length = Math.abs(lowerRightPoint.getX() - topLeftPoint.getX());
double height = Math.abs(topLeftPoint.getY() - lowerRightPoint.getY());
return length * height;
}
}
class Point {
private double x;
private double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
}
该题目比较简单就不进行分析
7-3 测验3-继承与多态
将测验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类中的静态方法,体现程序设计的多态性。
输入格式:
输入类型选择(1或2,不考虑无效输入)
对应图形的参数(圆或矩形)
输出格式:
图形的面积(保留两位小数)
代码如下:
import java.util.Scanner;
abstract class Shape {
public abstract double getArea();
}
class Circle extends Shape {
private double radius;
public Circle(double radius) {
if (radius <= 0) {
System.out.println("Wrong Format");
}
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}
class Rectangle extends Shape {
private Point topLeftPoint;
private Point lowerRightPoint;
public Rectangle(Point topLeftPoint, Point lowerRightPoint) {
this.topLeftPoint = topLeftPoint;
this.lowerRightPoint = lowerRightPoint;
}
@Override
public double getArea() {
double length = Math.abs(lowerRightPoint.getX() - topLeftPoint.getX());
double height = Math.abs(topLeftPoint.getY() - lowerRightPoint.getY());
return length * height;
}
}
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) {
System.out.println("Wrong Format");
return; // 结束程序
}
Shape circle = new Circle(radius);
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;
}
}
public static void printArea(Shape shape) {
System.out.printf("%.2f\n", shape.getArea());
}
}
class Point {
private double x;
private double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
}
类图如下:

代码难度如下:

分析
这道题目主要涉及面向对象的基本概念和输入输出的处理。其中,难点可能包括以下几个方面:
-
抽象类与继承:代码中使用了抽象类Shape,并通过Circle和Rectangle类进行继承。难点在于理解抽象类的作用以及如何正确地实现子类对抽象方法的覆写。
-
异常处理:代码中对输入进行了一些合法性检查,比如半径和坐标的合法性,需要确保对异常情况的处理是正确的。
-
输入输出:程序使用了Scanner类来进行输入操作,需要确保输入的格式正确并进行相应的处理。
-
方法调用:在main方法中调用printArea方法时传入不同的Shape对象,需要理解多态的概念以及方法的动态绑定机制。
-
类的设计:Point类的设计也是一个难点,需要理解如何设计合适的类来表示坐标点,并进行正确的信息封装和访问控制。
7-4 测验4-抽象类与接口
在测验3的题目基础上,重构类设计,实现列表内图形的排序功能(按照图形的面积进行排序)。
提示:题目中Shape类要实现Comparable接口。
其中,Main类源码如下(可直接拷贝使用):
public class Main {
public static void main(String\[\] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
ArrayList<Shape> list = new ArrayList<>();
int choice = input.nextInt();
while(choice != 0) {
switch(choice) {
case 1://Circle
double radiums = input.nextDouble();
Shape circle = new Circle(radiums);
list.add(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);
list.add(rectangle);
break;
}
choice = input.nextInt();
}
list.sort(Comparator.naturalOrder());//正向排序
for(int i = 0; i < list.size(); i++) {
System.out.print(String.format("%.2f", list.get(i).getArea()) + " ");
}
}
}
输入格式:
输入图形类型(1:圆形;2:矩形;0:结束输入)
输入图形所需参数
输出格式:
按升序排序输出列表中各图形的面积(保留两位小数),各图形面积之间用空格分隔。
代码如下
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Scanner;
abstract class Shape implements Comparable<Shape> {
public abstract double getArea();
@Override
public int compareTo(Shape other) {
return Double.compare(this.getArea(), other.getArea());
}
}
class Circle extends Shape {
private double radius;
public Circle(double radius) {
if (radius <= 0) {
System.out.println("Wrong Format");
}
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}
class Rectangle extends Shape {
private Point topLeftPoint;
private Point lowerRightPoint;
public Rectangle(Point topLeftPoint, Point lowerRightPoint) {
this.topLeftPoint = topLeftPoint;
this.lowerRightPoint = lowerRightPoint;
}
@Override
public double getArea() {
double length = Math.abs(lowerRightPoint.getX() - topLeftPoint.getX());
double height = Math.abs(topLeftPoint.getY() - lowerRightPoint.getY());
return length * height;
}
}
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
ArrayList<Shape> list = new ArrayList<>();
int choice = input.nextInt();
while (choice != 0) {
switch (choice) {
case 1://Circle
double radius = input.nextDouble();
if (radius <= 0) {
System.out.println("Wrong Format");
break;
}
Shape circle = new Circle(radius);
list.add(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);
list.add(rectangle);
break;
}
choice = input.nextInt();
}
list.sort(Comparator.naturalOrder());//正向排序
for (Shape shape : list) {
System.out.print(String.format("%.2f", shape.getArea()) + " ");
}
}
}
class Point {
private double x;
private double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
}
类图如下:

代码难度如下:

分析
该道题目涉及的难点主要包括抽象类与继承、异常处理、输入输出、方法调用和类的设计等方面。
-
抽象类与继承:代码中定义了抽象类Shape,并通过Circle和Rectangle类进行继承。这里需要理解抽象类的作用,以及在子类中如何实现对抽象方法的覆写。
-
异常处理:在Circle类的构造函数中对半径的合法性进行了检查,并输出错误信息。需要确保对输入的合法性进行正确的判断和处理。
-
输入输出:程序使用了Scanner类进行输入操作,需要确保对输入的格式进行正确的处理,以及对异常情况进行适当的处理。
-
方法调用:在main方法中调用printArea方法时,使用了Shape对象的多态特性。需要理解多态的概念以及方法的动态绑定机制。
-
类的设计:Point类的设计需要理解如何设计合适的类来表示坐标点,并进行正确的信息封装和访问控制。同时需要确保对坐标点的计算和使用是准确无误的。
针对这些难点,建议在阅读和理解代码的基础上,逐个进行测试和调试,确保对每个难点都有清晰的理解和正确的处理方式。如果在处理过程中遇到问题,可以逐个针对难点进行调试和咨询,以确保程序的正确性和稳定性。
三.踩坑心得
-
在写代码的时候使用了异常处理, 在
main方法中使用了异常处理,但是处理异常的方式比较简单粗暴,只是简单地打印了异常信息。更好的方式是根据具体情况进行处理。 -
写代码经常犯的错误是代码结构不够清晰,尤其
main方法包含了太多的逻辑,应该将一些功能拆分成独立的方法,提高可读性和可维护性。这样一旦有错误也便于改进而不是每次出现错误还要花很多时间理清结构,然后再对代码进行修改。 -
在写菜单系列中我经常出现的错误是输入验证存在问题,在代码中有一些输入验证的逻辑,但并不完善。
四.主要困难及改进建议
-
代码结构不清晰:经常将整个程序都写在了
Main类中,使得代码结构混乱,不易维护和理解。 建议将代码拆分成更小的函数或类,每个函数/类只负责一项具体的功能,提高可读性和可维护性。 -
功能过于集中:每次写代码时在
Main类中的main方法功能过于集中,承担了太多的职责,应该考虑将其拆分成多个方法或类,以实现单一职责原则。 -
架构不清晰:自己写的代码中经常存在中存在大量的业务逻辑和数据操作混合在一起的情况,应该考虑使用面向对象的方式进行架构,将数据和操作封装到对应的类中。
-
错误处理不完善:在写这几次大作业的时候,面对当输入不符合预期格式时,只是简单地打印错误信息并继续执行,而没有采取相应的措施,可能导致程序运行异常。所以写代码经常出错。
-
代码重复:经常写代码存在部分代码逻辑存在重复,应该经常考虑提取公共部分为单独的方法,以减少重复代码量。
- 异常处理不完整:在这几次大作业中写的代码存在使用了异常处理,但是具体的处理逻辑不够清晰,对于不同类型的异常可能需要做出不同的处理。经常没有考虑道多种情况导致经常存在问题提交代码的时候。需要更多地考虑异常的情况,并给出相应的处理方式。
五、总结
编写菜单系统的过程中,我遇到了许多挑战并从中获得了宝贵的经验。在代码编写中,我发现异常处理和代码结构是我经常犯错的地方。在处理异常时,我以往采用了比较简单粗暴的方式,只是简单地打印异常信息,而没有根据具体情况进行处理。这导致了程序的健壮性不够,因此在未来的项目中,我将更加注重异常的全面处理,针对不同类型的异常给出相应的处理方式。
另外,我也意识到自己经常在代码结构上犯错,主方法中包含了太多的逻辑,使得代码结构混乱不易维护。因此,在以后我会将代码拆分成更小的函数或类,每个函数/类只负责一项具体的功能,提高代码的可读性和可维护性。同时,我还要更加严谨尤其代码需要输入验证,确保程序能够稳定运行。
在未来的学习和项目中,我会更加注重代码架构的清晰性,遵循面向对象的原则,将数据和操作封装到对应的类中,避免功能过于集中和代码重复的问题。此外,我也会更加认真地考虑异常处理的情况,并给出相应的处理方式,以提高代码的健壮性和稳定性。通过不断总结经验和改进,我相信我能够成为一个更优秀的程序员。