Java博客作业(二)

nchulzr / 2023-04-28 / 原文

一、前言

题目集四

知识点:查找重复数据、删除重复数据、Arrays类、split方法处理字符串、ArrayList、字符串统计与排序、封装编程、数据转换处理、使用LocalDate类和ChronoUnit类处理日期问题、使用Integer类中的parselnt()等方法将字符串转换为其他数据类型等。

题量:中

难度:一般

题目集五

知识点:正则表达式处理数据、类间关系处理——聚合

题量:中

难度:一般,题目集五前几道题均为正则表达式的训练,难度不大,最后两题也是熟悉的日期题,还是原来的配方,熟悉的味道。

题目集六

知识点:菜单计价系统

题量:少

难度:难。(题目集六只有一道题,但是由于题目集四中的菜单3我并未完成,因此这次需要花时间去完善之前的代码,心里也早就打退堂鼓了。)

 

二、设计与分析 与 踩坑心得

题目集四

7-1  菜单计价程序-3

 题目如下:
7-1 菜单计价程序-3
分数 30
作者 蔡轲
单位 南昌航空大学
设计点菜计价程序,根据输入的信息,计算并输出总价格。

输入内容按先后顺序包括两部分:菜单、订单,最后以"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+英文空格+桌号+“:”+英文空格+当前桌的总价

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

输入样例:
在这里给出一组输入。例如:

麻婆豆腐 12
油淋生菜 9
table 1 2023/3/22 12/2/3
1 麻婆豆腐 2 2
2 油淋生菜 1 3
end
输出样例:
在这里给出相应的输出。例如:

table 1: 
1 麻婆豆腐 36
2 油淋生菜 27
table 1: 38
输入样例1:
在这里给出一组输入。例如:

麻婆豆腐 12
油淋生菜 9
table 1 2023/3/22 17/0/0
1 麻婆豆腐 2 2
2 油淋生菜 1 3
1 delete
end
输出样例1:
在这里给出相应的输出。例如:

table 1: 
1 麻婆豆腐 36
2 油淋生菜 27
table 1: 22
输入样例2:
在这里给出一组输入。例如:

麻婆豆腐 12
油淋生菜 9
table 1 2023/3/22 16/59/59
1 麻婆豆腐 2 2
2 油淋生菜 1 3
1 delete
end
输出样例2:
在这里给出相应的输出。例如:

table 1: 
1 麻婆豆腐 36
2 油淋生菜 27
table 1 out of opening hours
输入样例3:
在这里给出一组输入。例如:

麻婆豆腐 12
油淋生菜 9
table 1 2022/12/5 15/03/02
1 麻婆豆腐 2 2
2 油淋生菜 1 3
3 麻辣鸡丝 1 2
5 delete
7 delete
table 2 2022/12/3 15/03/02
1 麻婆豆腐 2 2
2 油淋生菜 1 3
3 麻辣鸡丝 1 2
7 delete
end
输出样例3:
在这里给出相应的输出。例如:

table 1: 
1 麻婆豆腐 36
2 油淋生菜 27
麻辣鸡丝 does not exist
delete error;
delete error;
table 2: 
1 麻婆豆腐 36
2 油淋生菜 27
麻辣鸡丝 does not exist
delete error;
table 1 out of opening hours
table 2: 63
输入样例4:
在这里给出一组输入。例如:

麻婆豆腐 12
油淋生菜 9
table 1 2022/12/3 19/5/12
1 麻婆豆腐 2 2
2 油淋生菜 1 3
3 麻辣鸡丝 1 2
table 2 2022/12/3 15/03/02
1 麻婆豆腐 2 2
2 油淋生菜 1 3
3 麻辣鸡丝 1 2
1 4 麻婆豆腐 1 1
7 delete
end
输出样例4:
在这里给出相应的输出。例如:

table 1: 
1 麻婆豆腐 36
2 油淋生菜 27
麻辣鸡丝 does not exist
table 2: 
1 麻婆豆腐 36
2 油淋生菜 27
麻辣鸡丝 does not exist
4 table 2 pay for table 1 12
delete error;
table 1: 63
table 2: 75
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
题目介绍

此题题干较长,这是第一次做菜单系列的题目,但是确是菜单3......看到这题本人是非常懵逼且吃惊的。

通过分析题干,首先需要根据题目给出的参考模板进行设计:菜品类(Dish)、菜谱类(Menu)、点菜记录类(Recod)、订单类(Order)。

Dish:包含菜品名称name和单价unit_price两个属性,保存一条菜品信息。getPrice(int portion)方法计算菜品价格的方法,输入参数是点菜的份额。

 

Menu:包含菜品数组dish[],保存所有菜品信息,提供Dish searchDish(String dishName)查找菜单中菜品 和 void addDish(String dishName,int unit_price)方法添加菜品到菜单中。
其中searchDish方法是根据菜品名称使用 equal 方法进行匹配,若菜单内无对应菜品,则输出菜品不存在的语句,相应代码如下:
 
Record:包含点餐序号orderNum、所点菜品dish、点菜份额portion,保存一条点菜记录信息。getPrice()方法计价,计算本条记录的价格。
 
Order:包含records[],代表一整个订单信息,并且有int getTotalPrice()方法计算订单的总价,Record addARecord(int orderNum,String dishName,int portion,int num)方法添加一条菜品信息到订单中,delARecordByOrderNum(int orderNum)方法根据序号删除一条记录findRecordByNum(int orderNum)方法根据序号查找一条记录。
其中,由于删去记录对点单最大的影响是结算价格,因此将方法返回类型设置为int,目的是直接返回删去对应记录后的订单价格。对应代码如下:
 

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

设计Main主类时,为了能够读取输入所有内容,使用while循环,将每一行读取的内容保存到数组temp中,并使用split()去除空格。使用if语句对temp长度count进行判定:

1、如果count=2,则说明:
a:输入为菜单行,数组第一个元素字符串为菜品名称,第二个为菜品单价。使用Menu类中的addDish添加菜品即可。
b:输入为delete行,此时数组第二个字符串元素为delete。
2、如果count=4,则说明:
a:输入为table信息行,由于桌号是按顺序排列的,因此初始化tablenum=0,之后每次tablenum++,输出table+tablenum+ : 。
b:输入为订单信息行,数组内第一个字符串为ordernum订单号,第二为dishname菜品名称,第三为portion份额,第四为amount份数。调用menu类中的searchDish方法查找菜单中对应菜品信息,如果没有查到,则输出(),否则添加信息到Order类中,并累加当前菜品总价。
3、如果匹配到end ,结束循环。
 
之后就是各项细节与功能完善与优化,如不同时间段的打折问题等还未处理。
由于时间紧迫,并没有接下去完善,半成品程序便直接撂下了。
 
 
7-2 有重复的数据
 题目如下:
7-2 有重复的数据
分数 10
作者 翁恺
单位 浙江大学
在一大堆数据中找出重复的是一件经常要做的事情。现在,我们要处理许多整数,在这些整数中,可能存在重复的数据。

你要写一个程序来做这件事情,读入数据,检查是否有重复的数据。如果有,输出“YES”这三个字母;如果没有,则输出“NO”。

输入格式:
你的程序首先会读到一个正整数n,n∈[1,100000],然后是n个整数。

输出格式:
如果这些整数中存在重复的,就输出:

YES
否则,就输出:

NO
输入样例:
5
1 2 3 1 4
输出样例:
YES
代码长度限制
16 KB
时间限制
800 ms
内存限制
64 MB
题目介绍

这道题主要考察如何快速判断是否存在重复数据,最开始我想通过一次性输入所有数据的方法减少运行时长,再使用双循环进行判断输出。如此输入的数据就是字符型,使用String类中的charAt()方法便可以轻松对字符串内的数据进行比较查重。

简单编写后运行,这时运行程序并没有显示:运行超时,而是答案错误,这是十分出乎我意料的。

 

调试了好一阵子才发现几个问题:

由于题目是先输入n,再换行输入n个数据,所以我的输入方式是有问题的,这是最初的输入方式:

 这样的话 s 保存的不是n个数据组成的字符串,而是换行符,需要再用一个nextLine()去保存换行符,修改后如下:

 这时依旧没有通过所有测试点,

之后发现每次输入一个数据都会用空格隔开,但是我并没有对此进行相关操作(这个时候还没有了解过split()方法,不会去除空格),因此程序运行会判断两个空格为重复数据,导致答案错误。因此我在遍历循环时,将i
++改成 i = i+2,想通过这种方法规避空格,但是测试点依旧过不去。
许久许久许久之后我才意识到输入的数据不一定都是一位数(题目样例给的都是一位数,造成了干扰误导),如果输入数据为多位数,那么 i + 2 便毫无作用,后面的判断将全盘出错。
这个时候我也是完全不知道改如何进行处理了,只好放弃这个思路。
(本次题目集的 7-7 引导了我们学习spilt()方法,如果早知道这个方法,就可以接着写下去了,也不会出那么多bug........)
此思路有缺陷的源码如下:
 1 import java.util.Scanner;
 2 
 3 public class Main {
 4     public static void main(String[] args){
 5         Scanner input = new Scanner(System.in);
 6         int n=input.nextInt();
 7         input.nextLine();
 8         String s = input.nextLine();
 9         int i=0;
10         int j=0;
11         int k = 0;
12         for(i = 0;i < s.length();i=i+2){
13             for(j = i + 2;j < s.length();j=j+2){
14                 if(s.charAt(i)==s.charAt(j))
15                 {
16                     k++;
17                     break;
18                 }
19             }
20         }
21         if(k==0) System.out.print("YES");
22         if(k!=0) System.out.print("NO");
23         }
24 }
View Code

换个思路:

既然一次性输入的方法我不能完成,那么我就一个一个输入整形数据存到数组里吧,面对大量数据要减轻运行负担,我最先想到的是二分法。
而二分法需要对数据先进行排序,通过查阅资料了解到java的Array类提供了sort()方法对数据进行自动排序,于是我便这样做了。
当我想要用二分法进行数据处理时,突然想到,既然是判断重复数据,那么我直接对一个数据进行判断,看它是否与前一个数据和后一个数据相等不就行了么,如果数据重复,那么它的前后必定有至少一个与其相等。
如此写下来,逻辑正确,运行时间也不会太大,最终通过了测试点。
源码如下:
 1 import java.util.Scanner;
 2 import java.util.Arrays;
 3 public class Main {
 4     public static void main(String[] args){
 5         Scanner input = new Scanner(System.in);
 6         int i;
 7         int j;
 8         int k=0;
 9         int n=input.nextInt();
10         input.nextLine();
11         int[] number=new int[n];
12         for(i=0;i<n;i++)
13             number[i]=input.nextInt();
14          Arrays.sort(number);
15         for(i=1;i<n-1;i++){
16             if(number[i-1]==number[i]||number[i+1]==number[i]){
17                 k++;
18                 break;
19             }
20         }
21         if(k==0||n==1) System.out.print("NO");
22         else if(k!=0&&n!=1) System.out.print("YES");
23 
24     }
25 }
View Code

 

 
 
题目集五
7-1 ——7-4 
这四题均为对正则表达式的训练,了解了正则表达式的书写原则过后,写起来轻轻松松,也使我认识到正则表达式的方便之处,可以大量减少题目的代码量,非常好用。
 
7-5 日期问题面向对象设计(聚合一)
7-5 日期问题面向对象设计(聚合一)
分数 50
作者 段喜龙
单位 南昌航空大学
参考题目7-2的要求,设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1900,2050] ,month∈[1,12] ,day∈[1,31] , 设计类图如下:

类图.jpg

应用程序共测试三个功能:

求下n天
求前n天
求两个日期相差的天数
注意:严禁使用Java中提供的任何与日期相关的类与方法,并提交完整源码,包括主类及方法(已提供,不需修改)

输入格式:
有三种输入方式(以输入的第一个数字划分[1,3]):

1 year month day n //测试输入日期的下n天
2 year month day n //测试输入日期的前n天
3 year1 month1 day1 year2 month2 day2 //测试两个日期之间相差的天数
输出格式:
当输入有误时,输出格式如下:
Wrong Format
当第一个数字为1且输入均有效,输出格式如下:
year-month-day
当第一个数字为2且输入均有效,输出格式如下:
year-month-day
当第一个数字为3且输入均有效,输出格式如下:
天数值
输入样例1:
在这里给出一组输入。例如:

3 2014 2 14 2020 6 14
输出样例1:
在这里给出相应的输出。例如:

2312
输入样例2:
在这里给出一组输入。例如:

2 1935 2 17 125340
输出样例2:
在这里给出相应的输出。例如:

1591-12-17
输入样例3:
在这里给出一组输入。例如:

1 1999 3 28 6543
输出样例3:
在这里给出相应的输出。例如:

2017-2-24
输入样例4:
在这里给出一组输入。例如:

0 2000 5 12 30
输出样例4:
在这里给出相应的输出。例如:

Wrong Format
代码长度限制
16 KB
时间限制
10000 ms
内存限制
64 MB
题目详情

题目7-5和7-6均为日期问题的迭代版本,要求根据给出的类图编写程序,本题给出的类图如下:

 

由类图可以看出本题主要类间关系为聚合:DateUtil类由Day类组成,Day由Month组成,Month由Year组成。各聚合类都有一个value元素表达当前类对象的值以及一个聚合到该类的类型元素构成聚合关系。相比之前只有Main类和DateUtil类,所有的处理方法都堆积在DateUtil类中,这次对程序中的元素及方法进行了规划处理,数据的处理更为严谨,使程序代码更加可视化、更符合面向对象编程要求。
编写程序时,我根据类图中给出的信息,首先编写Year类,之后分别是Month类、Day类、DateUtil类,逐步完成。
此程序已经编写过多次,虽然改写会遇到大大小小的bug,但大多都与之前碰到的问题大同小异,有了一定的经验调试起来效率高了许多。
 
SourceMonitor的生成报表内容如下:

源码如下:

import java.util.Scanner;

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

        int choice = input.nextInt();

        if (choice == 1) { // test getNextNDays method
            int m = 0;
            year = Integer.parseInt(input.next());
            month = Integer.parseInt(input.next());
            day = Integer.parseInt(input.next());

            DateUtil date = new DateUtil(year, month, day);

            if (!date.checkInputValidity()) {
                System.out.println("Wrong Format");
                System.exit(0);
            }

            
            m = input.nextInt();

            if (m < 0) {
                System.out.println("Wrong Format");
                System.exit(0);
            }

//             System.out.print(date.getDay().getMonth().getYear().getValue() + "-" + date.getDay().getMonth().getValue() + "-" + date.getDay().getValue() + " next " + m + " days is:");
            System.out.println(date.getNextNDays(m).showDate());
        } else if (choice == 2) { // test getPreviousNDays method
            int n = 0;
            year = Integer.parseInt(input.next());
            month = Integer.parseInt(input.next());
            day = Integer.parseInt(input.next());

            DateUtil date = new DateUtil(year, month, day);

            if (!date.checkInputValidity()) {
                System.out.println("Wrong Format");
                System.exit(0);
            }

            n = input.nextInt();

            if (n < 0) {
                System.out.println("Wrong Format");
                System.exit(0);
            }

//             System.out.print(date.getDay().getMonth().getYear().getValue() + "-" + date.getDay().getMonth().getValue()+date.getDay().getValue()+ " previous " + n + " days is:");
            System.out.println(date.getPreviousNDays(n).showDate());
        } else if (choice == 3) {    //test getDaysofDates method
            year = Integer.parseInt(input.next());
            month = Integer.parseInt(input.next());
            day = Integer.parseInt(input.next());

            int anotherYear = Integer.parseInt(input.next());
            int anotherMonth = Integer.parseInt(input.next());
            int anotherDay = Integer.parseInt(input.next());

            DateUtil fromDate = new DateUtil(year, month, day);
            DateUtil toDate = new DateUtil(anotherYear, anotherMonth, anotherDay);

            if (fromDate.checkInputValidity() && toDate.checkInputValidity()) {
                System.out.println(fromDate.getDaysofDates(toDate));
            } else {
                System.out.println("Wrong Format");
                System.exit(0);
            }
        }
        else{
            System.out.println("Wrong Format");
            System.exit(0);
        }        
    }
}

class DateUtil{
    private Day day = new Day();
    public DateUtil(){
        
    }
    public DateUtil(int y,int m,int d){
        day.setValue(d);
        day.getMonth().setValue(m);
        day.getMonth().getYear().setValue(y);
    }
    public Day getDay(){
        return day;
    }
    public void setDay(Day d) {
        day = d;
    }
    public boolean checkInputValidity(){
        if(day.getMonth().validate()&&day.getMonth().getYear().validate()){
            if(day.validate())
                return true;
            else return false;
        }
        else {
            return false;
        }
    }
    public boolean compareDates(DateUtil date){
        //前大于后,true
        if(day.getMonth().getYear().getValue() > date.getDay().getMonth().getYear().getValue())
            return true;
        else if(day.getMonth().getYear().getValue() == date.getDay().getMonth().getYear().getValue()&&day.getMonth().getValue() > date.getDay().getMonth().getValue())
            return true;
        else if(day.getMonth().getYear().getValue() == date.getDay().getMonth().getYear().getValue()&&day.getMonth().getValue() == date.getDay().getMonth().getValue()&&day.getMonth().getYear().getValue() == date.getDay().getMonth().getYear().getValue()&&day.getValue() > date.getDay().getValue())
            return true;
        else return false;
    }
    public boolean equalTwoDates(DateUtil date){
        //相等返回true
        if(day.getMonth().getYear().getValue() == date.getDay().getMonth().getYear().getValue()&&day.getMonth().getValue() == date.getDay().getMonth().getValue()&&day.getMonth().getYear().getValue() == date.getDay().getMonth().getYear().getValue()&&day.getValue() > date.getDay().getValue())
            return true;
        else return false;
    }
    public String showDate(){
        return (day.getMonth().getYear().getValue()+"-"+day.getMonth().getValue()+"-"+day.getValue());
    }
    public DateUtil getNextNDays(int n){
        int i;
        for(i=1;i<=n;i++){
            day.dayIncrement();      //day++;
            if(!day.validate()) {     //当day不合法,即day>mon_maxnum时,month++;
                day.resetMin();        //day复位为1;
                day.getMonth().monthIncrement();   //month++
                if(!day.getMonth().validate()) {   //当month不合法,即month>12时,year++
                    day.getMonth().resetMin();     //month复位为1 
                    day.getMonth().getYear().yearIncrement();   //year++
                    //此时日期为xx年1月1日
                    while(n-i>365) {     //while循环整年整年加,加快运行效率
                        if(day.getMonth().getYear().isLeapYear()) {
                            n-=366;     //闰年一年过去366天
                            day.getMonth().getYear().yearIncrement(); //year++
                            }
                        else {
                            n-=365;
                            day.getMonth().getYear().yearIncrement();
                            }
                        }//退出while循环后,再次变成一天一天加
                    }
                }
        }
        DateUtil a=new DateUtil(day.getMonth().getYear().getValue(),day.getMonth().getValue(),day.getValue());
        return a;
    }
    
    public DateUtil getPreviousNDays(int n){
        int i;
        for(i=1;i<=n;i++){
            day.dayReduction();      //day--;
            if(!day.validate()) {     //当day不合法,即day<1时,month--;
                day.getMonth().monthReduction();   //month--
                day.resetMax();        //day复位为max;
                if(!day.getMonth().validate()) {   //当month不合法,即month<1时,year--
                    day.getMonth().resetMax();     //month复位为12 
                    day.getMonth().getYear().yearReduction();   //year--
                    //此时日期为xx年12月31日
                    while(n-i>365) {    
                        if(day.getMonth().getYear().isLeapYear()) {
                            n-=366;     
                            day.getMonth().getYear().yearReduction(); //year--
                            }
                        else {
                            n-=365;
                            day.getMonth().getYear().yearReduction();
                            }
                        }//退出while循环后,再次变成一天一天减
                    }
                }
        }
        DateUtil a=new DateUtil(day.getMonth().getYear().getValue(),day.getMonth().getValue(),day.getValue());
        return a;        
    }
    
    
    public int getDaysofDates(DateUtil date){
        int dif=0;
        int n=0;
        if(compareDates(date)){
            //前大于后(this>date)
                if(date.getDay().getMonth().getYear().getValue()!=day.getMonth().getYear().getValue()){
                    //不同年
                    dif++;
                    for(;;dif++){
                        date.getDay().dayIncrement();     //day++;
                        if(!date.getDay().validate()) {
                            date.getDay().resetMin();//day=1
                            date.getDay().getMonth().monthIncrement();
                            if(!date.getDay().getMonth().validate()) {
                                date.getDay().getMonth().resetMin();          //month=1
                                date.getDay().getMonth().getYear().yearIncrement();//year++
                                //xx年1月1日
                                n=day.getMonth().getYear().getValue()-date.getDay().getMonth().getYear().getValue();
                                while(n>=1) {     //while循环整年整年加,加快运行效率
                                    if(date.getDay().getMonth().getYear().isLeapYear()) {
                                        dif+=366;
                                        date.getDay().getMonth().getYear().yearIncrement();
                                        n--;
                                        }
                                    else {
                                        dif+=365;
                                        date.getDay().getMonth().getYear().yearIncrement();
                                        n--;
                                        }
                                    }
                                }
                            }
                        if(date.showDate().equals(showDate())) {
                            break;
                        }
                    }
                }
                else{
                    //同一年
                    while(!date.showDate().equals(showDate())){
                        dif++;
                        date.getDay().dayIncrement();
                        if(!date.getDay().validate()) {
                            date.getDay().resetMin();
                            date.getDay().getMonth().monthIncrement();
                        }
                    }
                }
            }
        else{
            if(equalTwoDates(date)){
                //相等
                dif=0;
            }
            
            else{
                //前小于后(this<date)
                DateUtil t = new DateUtil(1999, 1, 1);
                t.getDay().setValue(date.getDay().getValue());
                date.getDay().setValue(day.getValue());
                day.setValue(t.getDay().getValue());
                
                t.getDay().getMonth().setValue(date.getDay().getMonth().getValue());
                date.getDay().getMonth().setValue(day.getMonth().getValue());
                day.getMonth().setValue(t.getDay().getMonth().getValue());
                
                t.getDay().getMonth().getYear().setValue(date.getDay().getMonth().getYear().getValue());
                date.getDay().getMonth().getYear().setValue(day.getMonth().getYear().getValue());
                day.getMonth().getYear().setValue(t.getDay().getMonth().getYear().getValue());
                
                if(date.getDay().getMonth().getYear().getValue()!=day.getMonth().getYear().getValue()){
                dif++;
                    for(;;dif++){
                    date.getDay().dayIncrement();     //day++;
                    if(!date.getDay().validate()) {
                        date.getDay().resetMin();
                        date.getDay().getMonth().monthIncrement();
                        if(!date.getDay().getMonth().validate()) {
                            date.getDay().getMonth().resetMin();          //month=1
                            date.getDay().getMonth().getYear().yearIncrement();//year++
                            //xx年1月1日
                            n=day.getMonth().getYear().getValue()-date.getDay().getMonth().getYear().getValue();
                            while(n>=1) {     //while循环整年整年加,加快运行效率
                                if(date.getDay().getMonth().getYear().isLeapYear()) {
                                    dif+=366;
                                    date.getDay().getMonth().getYear().yearIncrement();
                                    n--;
                                    }
                                else {
                                    dif+=365;
                                    date.getDay().getMonth().getYear().yearIncrement();
                                    n--;
                                    }
                                }
                            }
                        }
                    if(date.showDate().equals(showDate())) {
                        break;
                    }
                }
            }
            else{
                //同一年
                while(!date.showDate().equals(showDate())){
                    dif++;
                    date.getDay().dayIncrement();
                    if(!date.getDay().validate()) {
                        date.getDay().resetMin();
                        date.getDay().getMonth().monthIncrement();
                    }
                }
            }
            }
        }
        return dif;
    }

}

class Day{
    private int value;
    private Month month = new Month();;
    private int[] mon_maxnum = new int[]{31,31,28,31,30,31,30,31,31,30,31,30,31};
    public Day(){
  
    }
    public Day(int yearValue, int monthValue, int dayValue){
        month.getYear().setValue(yearValue);
        month.setValue(monthValue);
        value = dayValue;
    }
    public int getValue() {
        return value;
    }
    public Month getMonth() {
        return month;
    }
    public void setValue(int value) {
        this.value = value;
    }
    public void setMonth(Month month) {
        this.month = month;
    }
    public void resetMin() {
        value = 1;
    }
    public void resetMax() {
        if(month.getYear().isLeapYear()&&month.getValue()==2) {
            value=29;
        }
        else
            value = mon_maxnum[month.getValue()];
    }
    public boolean validate() {
        if(month.getYear().isLeapYear()&&month.getValue()==2) {
            if(value>=1&&value<=29)
                return true;
            else {
                return false;
            }
        }
        else if(value>=1&&value<=mon_maxnum[month.getValue()])
            return true;
        else {
            return false;
        }
    }
    public void dayIncrement() {
        value++;
    }
    public void dayReduction() {
        value--;
    }
}

class Month{
    private int value;
    private Year year = new Year();
    public Month() {
        
    }
    public Month(int yearValue, int monthValue) {
        year.setValue(yearValue);
        value = monthValue;
    }
    public int getValue() {
        return value;
    }
    public Year getYear() {
        return year;
    }
    public void setValue(int value) {
        this.value = value;
    }
    public void setYear(Year year) {
        this.year = year;
    }
    public void resetMin() {
        value = 1;
    }
    public void resetMax() {
        value = 12;
    }
    public boolean validate() {
        if(value>=1&&value<=12)
            return true;
        else return false;        
    }
    public void monthIncrement() {
        value++;
    }
    public void monthReduction() {
        value--;
    }
}

class Year{
    private int value;
    public Year() {
        
    }
    public Year(int value) {
        this.value = value;
    }
    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }
    public boolean isLeapYear(){
        if((value%4==0&&value%100!=0)||(value%400==0))
            return true;
        else return false;
    }
    public boolean validate() {
        if(value>=1900&&value<=2050)
            return true;
        else return false;
    }
    public void yearIncrement() {
        value++;
    }
    public void yearReduction() {
        value--;
    }
}
View Code

 

 
7-6 日期问题面向对象设计(聚合二)
题目7-6与7-5几乎只有给出的类图不同,本题给出类图如下:

相比7-5,7-6给出的类图更加合理。7-5以DateUtil类开始,一个一个连结Day类、Month类、Year类,虽然程序按部就班不会出大差错,但是会导致代码冗长杂乱,不易解读修改等。而7-6中以DateUtil为聚合中心连接其他类,Day类、Month类、Year类彼此之间无关联,代码耦合性降低,可读性更强。

虽然7-5(聚合一)和7-6(聚合二)相比之前迭代版本仅仅是对类间关系作了要求,但是我依旧花了许多时间在上面,究其原因是每次写程序时都太死板,测试点过了就收手,也不管代码模块是否合理。每次迭代时由于各模块相关性太强,一修改就相当于重写,大大降低了编程效率。

SourceMonitor的生成报表内容如下:

源码如下:

  1 import java.util.Scanner;
  2 
  3 public class Main {
  4     public static void main(String[] args) {
  5         Scanner input = new Scanner(System.in);
  6         int year = 0;
  7         int month = 0;
  8         int day = 0;
  9 
 10         int choice = input.nextInt();
 11 
 12         if (choice == 1) { // test getNextNDays method
 13             int m = 0;
 14             year = Integer.parseInt(input.next());
 15             month = Integer.parseInt(input.next());
 16             day = Integer.parseInt(input.next());
 17 
 18             DateUtil date = new DateUtil(year, month, day);
 19 
 20             if (!date.checkInputValidity()) {
 21                 System.out.println("Wrong Format");
 22                 System.exit(0);
 23             }
 24 
 25             m = input.nextInt();
 26 
 27             if (m < 0) {
 28                 System.out.println("Wrong Format");
 29                 System.exit(0);
 30             }
 31 
 32             System.out.print(date.showDate()+ " next " + m + " days is:");
 33             System.out.println(date.getNextNDays(m).showDate());
 34         } else if (choice == 2) { // test getPreviousNDays method
 35             int n = 0;
 36             year = Integer.parseInt(input.next());
 37             month = Integer.parseInt(input.next());
 38             day = Integer.parseInt(input.next());
 39 
 40             DateUtil date = new DateUtil(year, month, day);
 41 
 42             if (!date.checkInputValidity()) {
 43                 System.out.println("Wrong Format");
 44                 System.exit(0);
 45             }
 46 
 47             n = input.nextInt();
 48 
 49             if (n < 0) {
 50                 System.out.println("Wrong Format");
 51                 System.exit(0);
 52             }
 53 
 54             System.out.print(date.showDate()+ " previous " + n + " days is:");
 55             System.out.println(date.getPreviousNDays(n).showDate());
 56         } 
 57         else if (choice == 3) {    //test getDaysofDates method
 58             year = Integer.parseInt(input.next());
 59             month = Integer.parseInt(input.next());
 60             day = Integer.parseInt(input.next());
 61 
 62             int anotherYear = Integer.parseInt(input.next());
 63             int anotherMonth = Integer.parseInt(input.next());
 64             int anotherDay = Integer.parseInt(input.next());
 65 
 66             DateUtil fromDate = new DateUtil(year, month, day);
 67             DateUtil toDate = new DateUtil(anotherYear, anotherMonth, anotherDay);
 68 
 69             if (fromDate.checkInputValidity() && toDate.checkInputValidity()) {
 70                 System.out.println("The days between " + fromDate.showDate() + 
 71                         " and " + toDate.showDate() + " are:"
 72                         + fromDate.getDaysofDates(toDate));
 73             } else {
 74                 System.out.println("Wrong Format");
 75                 System.exit(0);
 76             }
 77         }
 78         else{
 79             System.out.println("Wrong Format");
 80             System.exit(0);
 81         }        
 82     }
 83 }
 84 
 85 class DateUtil{
 86     private Year year = new Year();
 87     private Day day = new Day();
 88     private Month month = new Month();
 89     private int[] mon_maxnum = new int[]{31,31,28,31,30,31,30,31,31,30,31,30,31};
 90     public DateUtil(){
 91         
 92     }
 93     public DateUtil(int y,int m,int d){
 94         year.setValue(y);
 95         month.setValue(m);
 96         day.setValue(d);
 97     }
 98     public Year getYear() {
 99         return year;
100     }
101     public Day getDay() {
102         return day;
103     }
104     public Month getMonth() {
105         return month;
106     }
107     public void setYear(Year year) {
108         this.year = year;
109     }
110     public void setDay(Day day) {
111         this.day = day;
112     }
113     public void setMonth(Month month) {
114         this.month = month;
115     }
116     public void setDayMin() {
117         day.setValue(1);
118     }
119     public void setDayMax() {
120         if(year.isLeapYear()&&month.getValue()==2) {
121             day.setValue(29);
122         }
123         else
124             day.setValue(mon_maxnum[month.getValue()]);
125     }
126     public boolean checkInputValidity(){
127         if(month.validate()&&year.validate()){
128             if(year.isLeapYear()&&month.getValue()==2) {
129                 if(day.getValue()>=1&&day.getValue()<=29) {
130                     return true;
131                 }
132                 else return false;
133             }
134             else if(day.getValue()>=1&&day.getValue()<=mon_maxnum[month.getValue()])
135                 return true;
136             else return false;
137         }
138         else {
139             return false;
140         }
141     }
142     public boolean compareDates(DateUtil date){
143         //前大于后,true
144         if(year.getValue() > date.getYear().getValue())
145             return true;
146         else if(year.getValue() == date.getYear().getValue()&&month.getValue() > date.getMonth().getValue())
147             return true;
148         else if(year.getValue() == date.getYear().getValue()&&month.getValue() == date.getMonth().getValue()&&day.getValue() > date.getDay().getValue())
149             return true;
150         else return false;
151     }
152     public boolean equalTwoDates(DateUtil date){
153         //相等返回true
154         if(year.getValue() == date.getYear().getValue()&&month.getValue() == date.getMonth().getValue()&&day.getValue() == date.getDay().getValue())
155             return true;
156         else return false;
157     }
158     public String showDate(){
159         return (year.getValue()+"-"+month.getValue()+"-"+day.getValue());
160     }
161     public DateUtil getNextNDays(int n){
162         int i;
163         for(i=1;i<=n;i++){
164             day.dayIncrement();      //day++;
165             if(year.isLeapYear()&&month.getValue()==2) {
166                 if(day.getValue()>29) {
167                  setDayMin();
168                  month.monthIncrement(); //month++
169                 }
170             }
171             else if(day.getValue()>mon_maxnum[month.getValue()]){     //当day>mon_maxnum时,month++;
172                 setDayMin();      //day复位为1;
173                 month.monthIncrement(); //month++
174             }
175             if(!month.validate()) {   //当month不合法,即month>12时,year++
176                     month.resetMin();     //month复位为1 
177                     year.yearIncrement();   //year++
178                     //此时日期为xx年1月1日
179                     while(n-i>365) {     //while循环整年整年加,加快运行效率
180                         if(year.isLeapYear()) {
181                             n-=366;     //闰年一年过去366天
182                             year.yearIncrement(); //year++
183                             }
184                         else {
185                             n-=365;
186                             year.yearIncrement();
187                             }
188                         }//退出while循环后,再次变成一天一天加
189                     }
190         }
191         DateUtil a=new DateUtil(year.getValue(),month.getValue(),day.getValue());
192         return a;
193     }
194     
195     public DateUtil getPreviousNDays(int n){
196         int i;
197         for(i=1;i<=n;i++){
198             day.dayReduction();      //day--;
199             if(year.isLeapYear()&&month.getValue()==3) {     //当day不合法,即day<1时,month--;
200                 if(day.getValue()<1) {
201                     day.setValue(29);
202                     month.monthReduction();//month--
203                 }
204             }
205             else if(day.getValue()<1) {    
206                 month.monthReduction();  //month--
207                 setDayMax();       //day复位为max;
208             }
209             if(!month.validate()) {   //当month不合法,即month<1时,year--
210                     month.resetMax();    //month复位为12 
211                     year.yearReduction();   //year--
212                     //此时日期为xx年12月31日
213                     while(n-i>365) {    
214                         if(year.isLeapYear()) {
215                             n-=366;     
216                             year.yearReduction(); //year--
217                             }
218                         else {
219                             n-=365;
220                             year.yearReduction();
221                             }
222                         }//退出while循环后,再次变成一天一天减
223                     }
224         }
225         DateUtil a=new DateUtil(year.getValue(),month.getValue(),day.getValue());
226         return a;        
227     }
228     
229     
230     public int getDaysofDates(DateUtil date){
231         int dif=0;
232         int n=0;
233         if(compareDates(date)){
234             //前大于后(this>date)
235                 if(date.getYear().getValue()!=year.getValue()){
236                     //不同年
237                     dif++;
238                     for(;;dif++){
239                         date.getDay().dayIncrement();     //day++;
240                         if(!date.checkInputValidity()) {
241                             date.setDayMin();//day=1
242                             date.getMonth().monthIncrement();
243                             if(!date.getMonth().validate()) {
244                                 date.getMonth().resetMin();          //month=1
245                                 date.getYear().yearIncrement();//year++
246                                 //xx年1月1日
247                                 n=year.getValue()-date.getYear().getValue();
248                                 while(n>=1) {     //while循环整年整年加,加快运行效率
249                                     if(date.getYear().isLeapYear()) {
250                                         dif+=366;
251                                         date.getYear().yearIncrement();
252                                         n--;
253                                         }
254                                     else {
255                                         dif+=365;
256                                         date.getYear().yearIncrement();
257                                         n--;
258                                         }
259                                     }
260                                 }
261                             }
262                         if(date.showDate().equals(showDate())) {
263                             break;
264                         }
265                     }
266                 }
267                 else{
268                     //同一年
269                     while(!date.showDate().equals(showDate())){
270                         dif++;
271                         date.getDay().dayIncrement();
272                         if(!date.checkInputValidity()) {
273                             date.setDayMin();
274                             date.getMonth().monthIncrement();
275                         }
276                     }
277                 }
278             }
279         else{
280             if(equalTwoDates(date)){
281                 //相等
282                 dif=0;
283             }
284             
285             else{
286                 //前小于后(this<date)
287                 DateUtil t = new DateUtil(1999, 1, 1);
288                 t.getDay().setValue(date.getDay().getValue());
289                 date.getDay().setValue(day.getValue());
290                 day.setValue(t.getDay().getValue());
291                 
292                 t.getMonth().setValue(date.getMonth().getValue());
293                 date.getMonth().setValue(month.getValue());
294                 month.setValue(t.getMonth().getValue());
295                 
296                 t.getYear().setValue(date.getYear().getValue());
297                 date.getYear().setValue(year.getValue());
298                 year.setValue(t.getYear().getValue());
299                 
300                   if(date.getYear().getValue()!=year.getValue()){
301                       //不同年
302                       dif++;
303                       for(;;dif++){
304                           date.getDay().dayIncrement();     //day++;
305                           if(!date.checkInputValidity()) {
306                               date.setDayMin();//day=1
307                               date.getMonth().monthIncrement();
308                               if(!date.getMonth().validate()) {
309                                   date.getMonth().resetMin();          //month=1
310                                   date.getYear().yearIncrement();//year++
311                                   //xx年1月1日
312                                   n=year.getValue()-date.getYear().getValue();
313                                   while(n>=1) {     //while循环整年整年加,加快运行效率
314                                       if(date.getYear().isLeapYear()) {
315                                           dif+=366;
316                                           date.getYear().yearIncrement();
317                                           n--;
318                                           }
319                                       else {
320                                           dif+=365;
321                                           date.getYear().yearIncrement();
322                                           n--;
323                                           }
324                                       }
325                                   }
326                               }
327                           if(date.showDate().equals(showDate())) {
328                               break;
329                           }
330                       }
331                   }
332                   else{
333                       //同一年
334                       while(!date.showDate().equals(showDate())){
335                           dif++;
336                           date.getDay().dayIncrement();
337                           if(!date.checkInputValidity()) {
338                               date.setDayMin();
339                               date.getMonth().monthIncrement();
340                           }
341                       }
342                   }
343            
344             }
345         }
346         return dif;
347     }
348 }
349 
350 class Day{
351     private int value;
352     public Day(){
353   
354     }
355     public Day(int value){
356         this.value = value;
357     }
358     public int getValue() {
359         return value;
360     }
361     public void setValue(int value) {
362         this.value = value;
363     }
364     public void dayIncrement() {
365         value++;
366     }
367     public void dayReduction() {
368         value--;
369     }
370 }
371 
372 class Month{
373     private int value;
374     public Month() {
375         
376     }
377     public Month(int value) {
378         this.value = value;
379     }
380     public int getValue() {
381         return value;
382     }
383     public void setValue(int value) {
384         this.value = value;
385     }
386     public void resetMin() {
387         value = 1;
388     }
389     public void resetMax() {
390         value = 12;
391     }
392     public boolean validate() {
393         if(value>=1&&value<=12)
394             return true;
395         else return false;        
396     }
397     public void monthIncrement() {
398         value++;
399     }
400     public void monthReduction() {
401         value--;
402     }
403 }
404 
405 class Year{
406     private int value;
407     public Year() {
408         
409     }
410     public Year(int value) {
411         this.value = value;
412     }
413     public int getValue() {
414         return value;
415     }
416     public void setValue(int value) {
417         this.value = value;
418     }
419     public boolean isLeapYear(){
420         if((value%4==0&&value%100!=0)||(value%400==0))
421             return true;
422         else return false;
423     }
424     public boolean validate() {
425         if(value>=1820&&value<=2020)
426             return true;
427         else return false;
428     }
429     public void yearIncrement() {
430         value++;
431     }
432     public void yearReduction() {
433         value--;
434     }
435 }
View Code

 

题目集六

7-1 菜单计价程序-4

题目介绍:

7-1 菜单计价程序-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+英文空格+桌号+“:”+英文空格+当前桌的原始总价+英文空格+当前桌的计算折扣后总价

输入样例:
在这里给出一组输入。例如:

麻婆豆腐 12
油淋生菜 9 T
table 31 2023/2/1 14/20/00
1 麻婆豆腐 1 16
2 油淋生菜 1 2
2 delete
2 delete
end
输出样例:
在这里给出相应的输出。例如:

table 31: 
1 num out of range 16
2 油淋生菜 18
deduplication 2
table 31: 0 0
输入样例1:
份数超出范围+份额超出范围。例如:

麻婆豆腐 12
油淋生菜 9 T
table 31 2023/2/1 14/20/00
1 麻婆豆腐 1 16
2 油淋生菜 4 2
end
输出样例1:
份数超出范围+份额超出范围。例如:

table 31: 
1 num out of range 16
2 portion out of range 4
table 31: 0 0
输入样例2:
桌号信息错误。例如:

麻婆豆腐 12
油淋生菜 9 T
table a 2023/3/15 12/00/00
1 麻婆豆腐 1 1
2 油淋生菜 2 1
end
输出样例2:
在这里给出相应的输出。例如:

wrong format
输入样例3:
混合错误:桌号信息格式错误+混合的菜谱信息(菜谱信息忽略)。例如:

麻婆豆腐 12
油淋生菜 9 T
table 55 2023/3/31 12/000/00
麻辣香锅 15
1 麻婆豆腐 1 1
2 油淋生菜 2 1
end
输出样例3:
在这里给出相应的输出。例如:

wrong format
输入样例4:
错误的菜谱记录。例如:

麻婆豆腐 12.0
油淋生菜 9 T
table 55 2023/3/31 12/00/00
麻辣香锅 15
1 麻婆豆腐 1 1
2 油淋生菜 2 1
end
输出样例4:
在这里给出相应的输出。例如:

wrong format
table 55: 
invalid dish
麻婆豆腐 does not exist
2 油淋生菜 14
table 55: 14 10
输入样例5:
桌号格式错误(以“table”开头)+订单格式错误(忽略)。例如:

麻婆豆腐 12
油淋生菜 9 T
table a 2023/3/15 12/00/00
1 麻婆 豆腐 1 1
2 油淋生菜 2 1
end
输出样例5:
在这里给出相应的输出。例如:

wrong format
输入样例6:
桌号格式错误,不以“table”开头。例如:

麻婆豆腐 12
油淋生菜 9 T
table 1 2023/3/15 12/00/00
1 麻婆豆腐 1 1
2 油淋生菜 2 1
tab le 2 2023/3/15 12/00/00
1 麻婆豆腐 1 1
2 油淋生菜 2 1
end
输出样例6:
在这里给出相应的输出。例如:

table 1: 
1 麻婆豆腐 12
2 油淋生菜 14
wrong format
record serial number sequence error
record serial number sequence error
table 1: 26 17
其他用例请参考公开的测试用例

代码长度限制
50 KB
时间限制
1000 ms
内存限制
64 MB
题目介绍

由于之前菜单计价程序-3都没有写完,之后也没有太放在心上,所以再次看到这个2k字的题目我内心的发慌且劝退的,一度想要逃避。不过该面对的还得面对,逃不掉哎!

首先是接着之前菜单计价程序-3的半成品代码进行续写,对于主类与各类间关系进行完善。

之后仔细看了看题目的要求,我在题目给出的模板类的基础上,另外添加了Table 类和Time类。

Time类:

Time类用来处理时间,将系统读取到的输入的字符串时间信息处理为程序需要的信息。Time类有两个属性:int [] TenTime 和 int [] TenDate,分别用来存放某一天的时间和日期。类中提供setTenDate方法和setTenTime方法将程序读到的字符串时间信息转化成int型方便后续处理。对应代码如下:

 

 

由于题目中表明,在周一到周五的特定时间将对菜品进行打折处理,因此需要有一个判断日期为周几的方法——getDayofWeek()。编写这个方法时,我使用了LocalDate类中的getdayogweek方法进行处理,对应代码如下:

 

而对于店铺具体时间的处理,我在getTimeofDay()方法中将十进制的时间转化成秒的总和,以此进行时间判断,对应部分代码如下:

 

Table类:

Table类中有tableNum属性代表桌号、discount属性代表本桌订单对应折扣、sumprice代表总价,并调用Order类和Time类进行相关计算处理。类中主要有两个方法:

1、void discount(int timeofday,int dayofweek),此方法通过传入经Time类处理的时间与日期数据得出菜品具体折扣。具体代码如下:

 

2、Gettottalprice(),此方法用来计算菜品总价,并输出相应语句并对非法输入的时间段菜单进行处理。具体代码如下:

 

由于之前菜单3并未完成,所以这次接着上次的代码写时遇到了许多本应之前解决的问题。菜单3和菜单4有着 一定的区别,比如当我能够正常输出计算时,才发现菜单4的桌号是随机输入的,而菜单3是按顺序来的,因此我写的程序在这次题目中无法通过。此外此次菜单4还添加了特价菜系统和代点菜功能,要想实现这些功能我需要在目前代码上再进行一个不小的修整。询问其他同学,也是都没有拿到多少分,于是也慢慢放弃,能写多少写多少,但是由于并未完善,并没有拿到分。

 

三、改进建议

1、菜单-3与菜单-4:仔细分析题目需求,对类与类间的关系做好规划,分清各个类的功能与权限,后续再对现有的进度进行完善,直面困难,好好学习,不要再堆到下一次迭代。

2、题目集四——7-2有重复的数据:最初的思路较为可靠,一次性输入所有数据,使用spilt()方法去除空格处理字符串,再进行判定查重,按照最开始的想法进行修改。

3、关于正则表达式:学了就要用,而不是仅仅知道,要记住正则表达式的使用规则,不要每次书写都要查阅资料。

4、题目集五——7-5 与7-6 日期问题面向对象设计(聚合),所写程序代码冗杂,各模块耦合性太强。需要将各个模块功能尽可能独立,不要每次迭代一个版本就开发出一个全新版本,费时费力,要使代码方便修改。

四、总结反思

 通过这三次的题目集,我学会了正则表达式的使用、类间聚合关系的处理、使用Array类进行数据处理、使用spilt()去除空格等字符、使用Integer类中parseInt()转化数据类型,了解LocalDate类中of()、isAfter()、isBefore()、until()等方法的使用规则,了解ChronoUnit类中DAYS、WEEKS、MONTHS等单位的用法。
此外,我对面向对象这门课程的认识更加清晰,这门课程不同于C语言,复杂度更高,耗时更多,更容易拉开差距。
两次菜单问题的战败也使我清楚自己的实力真的很差,需要努力提升自己,自律一点,不要看到问题就打退堂鼓,要敢于面对克服苦难。
每次写日期类问题时,虽然内容大同小异,但是却要耗费大量时间,这使得我认识到我的代码结构不清晰,我需要好好规划自己的代码结构,不能想到哪就写哪,要有长远点的目光,不可止于当下。