关于PTA第二次大作业的总结

 

一.前言

这一次的作业,总体来说是有一定难度的,主要考察了类与对象的关系,java封装的技术特性,字符串的使用和正则表达式的使用等,还有java类的设计原则,题量比之前的作业减少了,但是难度在慢慢上升。特别是习题六,代码的数量上来了,关于类的设计就要谨慎。

二.设计与分析

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

刚开始看这道题目的时候,我是没什么头绪的,我是最后才来做这道题的。源码如下:
 1 import java.util.*;
 2 
 3 public class Main{   
 4     public static void main (String[] args){
 5 //         Scanner input = new Scanner(System.in);
 6 //         int i = 0;
 7 //         Dish dish[] = new Dish();
 8 //        do{
 9 //            dish[i].name = input.next();
10 //            dish[i].unit_price = input.nextInt();
11 //        }
12         
13     }
14 }
15 class Dish{ 
16     String name;//菜品名称
17     int unit_price;//单价
18    
19     Dish(){
20         
21     }
22     Dish(String name,int unit_price){
23         this.name = name;
24         this.unit_price = unit_price;
25     }
26     
27     public int getPrice(int portion){//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份)
28         if(portion == 1)
29             return unit_price*1;
30         if(portion == 2)
31             return unit_price*1.5;
32         if(portion == 3)
33             return unit_price*2;
34     }
35 }
36 class Menu{
37     Dish[] dishs;//菜品数组,保存所有菜品信息
38     
39     public  Dish searchDish(String dishName){//根据菜名在菜谱中查找菜品信息,返回Dish对象。
40         for(int i = 0;i < dishs.length;i++){
41             if(dishs[i].equals(dishName)){
42                 return dishs[i];
43             }
44         }
45     }
46     public Dish addDish(String dishName,int unit_price){//添加一道菜品信息
47        // dishs[dishs.length] = new Dish(dishName,unit_price);
48     }
49     
50 }
51 class Record{
52     int orderNum;//序号
53     Dish d;//菜品
54     int portion;//份额(1/2/3代表小/中/大份)
55     
56     Record(){
57         
58     }
59     //Record(int orderNum,String dishName,int portion,int portion
60       //  this.orderNUm = orderNum;
61 //         d.dishName = dishName;
62 // //         d.portion
63     //}
64 
65     
66     public int getPrice(){//计价,计算本条记录的价格\\
67        int result ;
68        if(portion == 1){
69            result = d.unit_price*1;
70        }
71        if(portion == 2)
72            result =(int) ( d.unit_price*1.5);
73        if(portion == 3)
74            result = d.unit_price*2;
75     }
76 }
77 // class Order{
78 //     Record[] records;//保存订单上每一道的记录
79     
80 //     int getTotalPrice(){//计算订单的总价
81 //         int sum = 0;
82 //         for(i = 0; i < records.length;i++){
83 //             sum += records[i].getPrice();
84 //         }
85 //     }
86 //     Record addARecord(int orderNum,String dishName,int portion,int num){//添加一条菜品信息
87 //         this.orderNum = orderNum;
88 //         d.dishName = dishName;
89 //         d.portion = portion;
90 //         this.num = num;
91 //     }
92 //     delARecordByOrderNum(int orderNum){//根据序号删除一条记录
93 //         Record[num] = 
94 //     }
95 //     findRecordByNUm(int orderNum){////根据序号查找一条记录
96        
97 //     }
98 // }
可以看到笔者的代码还不完整,还有一些功能没有完善,仅仅只有一些框架,按照题目意思:menu类里有dish对象,order里有record对象。这些类之间为依赖关系,测试如下:
可以看到只得了一分。

                                                                       

       后面就不知道怎么做了,总在纠结要不要用二维数组来存储输入的信息,然后后面的具体方法的实现就没怎么写,最够也没写出这道题。

生成的类图如下:

 

 

7-5 日期问题面向对象设计(聚合一)
分数 50
作者 段喜龙
单位 南昌航空大学

参考题目7-2的要求,设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1900,2050] ,month∈[1,12] ,day∈[1,31] , 设计类图如下:

类图.jpg

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

  1. 求下n天
  2. 求前n天
  3. 求两个日期相差的天数

注意:严禁使用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

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

运行结果如下:

 这题的话,在DateUtil类中有Day类对象,Day类中有Month对象,在Month类中有Year对象,这些类之间的关系都是聚合关系;这个题目更好解释了类与类之间的关系,如下图:

day对象调用month对象,month对象再调用year对象,year对象调用setValue方法,从而实现改变年份。我写的时候对年份的判定老是出现错误,其实参照习题四的题目就行了。在下写求两个日期的之间的天数,我用的是循环的方法,若前面的日期更小,则调用下N天的函数,循环N次;若前面的日期较大,则调用求上N天的方法,循环N次,这样就得到了两个日期之间的天数。相应的代码如下:

 1 public int getDaysofDates(DateUtil date){
 2         int n = 0;int flag = 0;
 3         if(compareDates(date) ){
 4             flag = 1;
 5         }
 6         else
 7             flag = 0;
 8         if(flag == 0){
 9             for( ; this.equalTwoDates(date) == false ; n++){
10               if(day.getMonth().getValue() != 12){
11                 if(day.getMonth().getValue() == 2){
12                     if(day.getMonth().getYear().isLeapYear()){
13                         if(day.getValue() != 29)
14                             day.dayIncrement();
15                         else{
16                             day.resetMin();
17                             day.getMonth().monthIncrement();
18                         }
19                     }
20                     else{//不是闰年
21                         if(day.getValue() != 28)
22                             day.dayIncrement();
23                         else{
24                             day.resetMin();
25                             day.getMonth().monthIncrement();
26                         }
27                     }
28                 }//2月
29                 else{//不是二月
30                     if(day.getMonth().getValue() == 1 || day.getMonth().getValue() == 3 || day.getMonth().getValue() == 5 || day.getMonth().getValue() == 7 || day.getMonth().getValue() == 8 || day.getMonth().getValue() == 10){
31                         if(day.getValue() != 31)
32                             day.dayIncrement();
33                         else{
34                             day.resetMin();
35                             day.getMonth().monthIncrement();
36                         }
37                             
38                     }
39                     else {
40                         if(day.getValue() != 30)
41                             day.dayIncrement();
42                         else{
43                             day.resetMin();
44                             day.getMonth().monthIncrement();
45                         }
46                     }
47       
48                 }
49             }
50             else{ //是12月
51                 if(day.getValue() != 31)
52                     day.dayIncrement();
53                 else{
54                     day.resetMin();
55                     day.getMonth().resetMin();
56                     day.getMonth().getYear().yearIncrement();
57                 }
58             }
59          }
60         }
61         else {
62             for( ; this.equalTwoDates(date) == false ; n++ ){
63                 if(day.getMonth().getValue() == 1){
64                  if(day.getValue() == 1){
65                      day.resetMax();
66                      day.getMonth().resetMax();
67                      day.getMonth().getYear().yearReduction();
68                  }
69                  else{
70                      day.dayReduction();
71                  }
72              } 
73              else {
74                      if(day.getValue() == 1){
75                          day.getMonth().monthReduction();
76                          day.resetMax();
77                      }
78                      else
79                          day.dayReduction();
80              }    
81             }
82         }
83              
84         return n;
85     }

这个题目将一个功能交给一个方法实现,体现了java中的单一职责原则,代码实现过程也更好写。

生成的类图如下:

生成的类图,由于都在一个java文件中,main与其他类都有依赖关系,不完全符合题目的要求。

 

 

7-6 日期问题面向对象设计(聚合二)
分数 34
作者 段喜龙
单位 南昌航空大学

参考题目7-3的要求,设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1820,2020] ,month∈[1,12] ,day∈[1,31] , 设计类图如下:

类图.jpg

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

  1. 求下n天
  2. 求前n天
  3. 求两个日期相差的天数

注意:严禁使用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且输入均有效,输出格式如下:
    year1-month1-day1 next n days is:year2-month2-day2
     
  • 当第一个数字为2且输入均有效,输出格式如下:
    year1-month1-day1 previous n days is:year2-month2-day2
     
  • 当第一个数字为3且输入均有效,输出格式如下:
    The days between year1-month1-day1 and year2-month2-day2 are:值
     

输入样例1:

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

3 2014 2 14 2020 6 14
 

输出样例1:

在这里给出相应的输出。例如:

The days between 2014-2-14 and 2020-6-14 are:2312
 

输入样例2:

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

2 1834 2 17 7821
 

输出样例2:

在这里给出相应的输出。例如:

1834-2-17 previous 7821 days is:1812-9-19
 

输入样例3:

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

1 1999 3 28 6543
 

输出样例3:

在这里给出相应的输出。例如:

1999-3-28 next 6543 days is:2017-2-24
 

输入样例4:

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

0 2000 5 12 30
 

输出样例4:

在这里给出相应的输出。例如:

Wrong Format

 

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

这道题和之前那到题虽然题目类似,但是类与类之间的关系不一样。DateUtil类中有Day,Mnoth和Year对象,它们之间的关系为DateUtil类与Day类,Month类,Year类都聚合,而Day,Month,Year之间没有关系,符合迪米特法则,类的耦合性更低。

现在在DateUtil类中,就可以用this.属性.方法直接调用想用的方法了。

笔者在DateUtil类中添加有关月份的数组,便于DateUtil的对象直接使用。通过这个题目,我学到了迪米特法则的使用,降低类与类之间的耦合性,使得程序易于维护。

生成的类图如下:

 

 

 题目集六.

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

 这个题目比之前的题目添加了更多的异常情况,测试点也变得更多,笔者没有写出来。我的代码如下:

import java.util.*;

public class Main{   
    public static void main (String[] args){
        Scanner input = new Scanner(System.in);
        
        int dishFlag = 0;
        int tableNum = 0;
        String[] str= new String[100];//输入的字符串数组
        
        Menu menu = new Menu();
       
       
        Tables tables = new Tables();//桌子数组
     
        int tableFlag = -1;//桌子号
        
        int i = -1;
        do {
            i++;
            str[i] = input.nextLine();
            
            //System.out.println(str[i-1]);
        }while(!str[i].matches("end"));//输入信息
        
        //菜单处理
        int dishNum = 0;
        for(i = 0  ; i < str.length ; i++) {
            if(!(str[i].charAt(0) == 't')){
                String[] dishString = str[i].split(" ");

                if(!dishString[1].matches("[0-9]|[1-9][0-9]|[1-9][0-9][0-9]")) {
                    System.out.println("wrong format");
                }
                else {
                    if(Integer.parseInt(dishString[1]) > 0 && Integer.parseInt(dishString[1] ) < 300) {
                        menu.addDish(dishString[0], Integer.parseInt(dishString[1]));
                        if(dishString.length == 3)
                            menu.getDishs().get(dishNum).setSpecial(dishString[2]);
                        
                        else
                            menu.getDishs().get(dishNum).setSpecial("F");
                        
                        dishNum++;
                        }
                    
                    
                    else {//菜价超出范围
                        System.out.println(dishString[0] + " price out of range " + dishString[1]);
                    
                    }
                }
                
                
            }
            if(str[i].charAt(0) == 't') {//到了桌号标识
                dishFlag = i-1;//菜单的下标
                break;
            }
                
        }
        
        //处理桌号
        for( i = dishFlag + 1; i < str.length ; i++) {
            String[] tableString  = str[i].split(" ");
            
            if(str[i].charAt(0) == 't') {//桌号标识
                
                if(tableString[0].matches("table")) {
                    
                    if(!tableString[1].matches("[1-9]|[1-9][0-9]|[1-9][0-9][0-9]") ) {
                        System.out.println("wrong format");
                    }
                    else {//桌号是数字
                        if(!(Integer.parseInt(tableString[1]) >= 1) && !( Integer.parseInt(tableString[1]) <= 55) ){
                            System.out.println(tableString[1] + " table num out of range");
                        }
                        else {
                            
                            tables.addATable();
                            tables.getTables().get(tableNum).setTableNum(Integer.parseInt(tableString[1]));
                            tables.getTables().get(tableNum).setTime1(tableString[2]);
                            tables.getTables().get(tableNum).setTime2(tableString[3]);
                            System.out.println(tableString[0] +" "+ tableString[1] +":");
                            
                        }
                    }
                    
                     
                    //else if(tableString[2].matches("[1-2][1-9][1-9][1-9]/[]"))
                    
                }
                else {//桌号标识错误
                    
                }
                
                
            }
            
            if(!(str[i].charAt(0) == 't') && !str[i].contains("delete") && tableString.length == 4) {//点菜记录处理
                boolean recordIsTrue = true;
        
                if(tableString.length == 2) {//混杂的菜谱信息,
                    System.out.println("invalid dish");
                    continue;//忽略这条菜谱
                }
                if(tableString.length == 4) {//点菜记录
                        if(!tableString[2].matches("[1-9]")) {//份额格式错误
                            recordIsTrue = false;
                            System.out.println("wrong format");
//                
                        }
                        if(tableString[2].matches("[1-9]")) {//份额为数值
                            if(menu.searchDish(tableString[1]) != null) {//找到了菜名
                                    if(menu.searchDish(tableString[1]).getSpecial() == "T") { //特价菜
                                        if((tableString[2] != "1" || tableString[2] != "3")) {
                                            System.out.println(tableString[0] + "portion out of range" + tableString[2]);
                                            recordIsTrue = false;
                                        }
                                        else {//普通菜
                                            if((tableString[2] != "1" || tableString[2] != "2" || tableString[2] != "3")) {
                                                System.out.println(tableString[0] + "portion out of range" + tableString[2]);
                                                recordIsTrue  = false ;
                                            }
                                        }
                            
                                    }
                            }
                            else {
                                
                            }
                            
                                
                        }
                        if(!tableString[3].matches("[1-9]|[1-9][0-9]")) {//份数非法
                            recordIsTrue = false;
                            System.out.println("wrong format");
                        }
                        if(tableString[3].matches("[1-9]|[1-9][0-9]")) {//份数越界
                            if(!(Integer.parseInt(tableString[3]) >= 1 && Integer.parseInt(tableString[3]) <= 15)) {
                                System.out.println(tableString[0] + " num out of range " + tableString[3]);
                                recordIsTrue = false;
                            }
                        }

                if(tableString.length == 4 && recordIsTrue == true) {//添加点菜记录
                    tables.getTables().get(tableNum).getOrder().addARecord(Integer.parseInt(tableString[0]), 
                            tableString[1], Integer.parseInt(tableString[2]), Integer.parseInt(tableString[3]));
                }
                
            }//点菜结束
            if(str[i].contains("delete") && tableString.length == 2) {//删除记录
                tables.getTables().get(tableNum).getOrder().delARecordByOrderNum(Integer.parseInt(tableString[0]));
            }
                
            if(str[i].matches("end")) {
                break;
            }
          }//点菜记录的处理
            
        
        
        }   
        
   }
}
class Dish { 
    String name;//菜品名称
    int unit_price;//单价
    String special ;//特价菜标识
   
    Dish(){
        
    }
    Dish(String name,int unit_price){
        this.name = name;
        this.unit_price = unit_price;
    }
    
    public String getName() {
        return this.name;
    }
    
    public void setName(String name) {
        this.name =  name;
    }
    public int  getUnit_Price() {
        return this.unit_price;
    }
    public void setUnit_Price(int unit_price) {
        this.unit_price = unit_price;
    }
    public String getSpecial() {
        return special;
    }
    public void setSpecial(String special) {
        this.special = special;
    }
    public int getPrice(int portion){//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份)
        int result = 0;
        if(portion == 1)
            result = unit_price*1;
        if(portion == 2)
            result =  (int)(unit_price*1.5);
        if(portion == 3)
            result = unit_price*2;
        return result;
    }
}
class Menu{
    private  ArrayList<Dish> dishs = new ArrayList<>() ;//菜品数组,保存所有菜品信息
    private int dishNum = 0;
   
    
    Menu(){
        super();
    }
    
    
    public ArrayList<Dish> getDishs() {
        return dishs;
    }


    public void setDishs(ArrayList<Dish> dishs) {
        this.dishs = dishs;
    }


    public  Dish searchDish(String dishName){//根据菜名在菜谱中查找菜品信息,返回Dish对象。
        for(int i = 0; i < dishs.size() ; i++){
            if(dishs.get(i).getName() == dishName){
                return dishs.get(i);
            }
              
        }
        return null;
    }
   
    public void addDish(String dishName,int unit_price){//添加一道菜品信息
        Dish dish = new Dish();
        dish.setName(dishName);
        dish.setUnit_Price(unit_price);
        dishs.add(dish);
        
    }
    
}

class Table{
    
    int  tableNum;//桌号
    String time1;//日期
    String time2;//时间
    Order order = new Order();//点菜记录
    String[] delRecord = new String[3];//删除记录
    String[] addRecord = new String[3];//代点菜记录
    Table(){
        
    }
    
    public Table(int tableNum, String time1, String time2, Order order, String[] delRecord, String[] addRecord) {
        super();
        this.tableNum = tableNum;
        this.time1 = time1;
        this.time2 = time2;
        this.order = order;
        this.delRecord = delRecord;
        this.addRecord = addRecord;
    }

    public int getTableNum() {
        return tableNum;
    }

    public void setTableNum(int tableNum) {
        this.tableNum = tableNum;
    }

    public String getTime1() {
        return time1;
    }

    public void setTime1(String time1) {
        this.time1 = time1;
    }

    public String getTime2() {
        return time2;
    }

    public void setTime2(String time2) {
        this.time2 = time2;
    }

    public Order getOrder() {
        return order;
    }

    public void setOrder(Order order) {
        this.order = order;
    }

    public String[] getDelRecord() {
        return delRecord;
    }

    public void setDelRecord(String[] delRecord) {
        this.delRecord = delRecord;
    }

    public String[] getAddRecord() {
        return addRecord;
    }

    public void setAddRecord(String[] addRecord) {
        this.addRecord = addRecord;
    }

    
}
class Time{
    public static boolean CheckTime1Validity(String time1) {
        String[] str = time1.split("/");
        if(str[0].matches("[1-9][0-9][0-9][0-9]") && 
                str[1].matches("[1-9]|[1-9][0-9]") && str[2].matches("[1-9]|[1-9][0-9]")) {
            return true;
        }
        else {
            return false;
        }
            
    }
    public static boolean CheckTime1Range(String time1) {
        String[] str = time1.split("/");
        int year = Integer.parseInt(str[0]);
        int month = Integer.parseInt(str[1]);
        int day = Integer.parseInt(str[2]);
        int[] mon_Max = {0,31,28,31,30,31,30,31,31,30,31,30,31};
        if(year >= 2022 && year <= 2023 && month >= 1 && month <= 12 && day >=1 && day <= mon_Max[month]){
            return true;
            
        }
        else
            return false;
    }
    public static boolean CheckTime2Validity(String time2) {
        String[] str = time2.split("/");
        if(str[0].matches("[1-9]|[1-9][0-9]") && 
                str[1].matches("[1-9]|[1-9][0-9]") && str[2].matches("[1-9]|[1-9][0-9]")) {
            return true;
        }
        else
            return false;
    }
    public static boolean CheckTime2Range(String time2){
        String[] str = time2.split("/");
        int hour = Integer.parseInt(str[0]);
        int minute = Integer.parseInt(str[1]);
        int second = Integer.parseInt(str[2]);
        if(hour > 0 && hour < 23 && minute > 0 && minute < 60 && second > 0 && second < 60)
            return true;
        else
            return false;
        
    }
}
class Tables{
    ArrayList<Table> tables = new ArrayList<>();

    public Tables() {
        super();
        // TODO 自动生成的构造函数存根
    }

    public Tables(ArrayList<Table> tables) {
        super();
        this.tables = tables;
    }

    public ArrayList<Table> getTables() {
        return tables;
    }

    public void setTables(ArrayList<Table> tables) {
        this.tables = tables;
    }
    public void addATable() { 
        Table table = new Table();
        tables.add(table);
    }
}

class Record{//点菜记录
    int orderNum;//序号
    Dish d;//菜品
    int portion;//份额(1/2/3代表小/中/大份)
    int num;//份数
    
    Record(){
        
    }

    public Record(int orderNum, Dish d, int portion, int num) {
        super();
        this.orderNum = orderNum;
        this.d = d;
        this.portion = portion;
        this.num = num;
    }
    
    public int getOrderNum() {
        return orderNum;
    }

    public void setOrderNum(int orderNum) {
        this.orderNum = orderNum;
    }
    
    public Dish getD() {
        return d;
    }

    public void setD(Dish d) {
        this.d = d;
    }

    public int getPortion() {
        return portion;
    }

    public void setPortion(int portion) {
        this.portion = portion;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public int  getPrice(){//计价,计算本条记录的价格 
        int result;
        result = d.getPrice(portion)*num;
        return result;
    }
}
class Order{//保存用户点的所有菜的信息。//点菜记录
    ArrayList<Record> records = new ArrayList<>();//保存订单上每一道的记录
    private int RecordNum = 0;
    public Record getRecord(int i) {
        return records.get(i);
    }
    public int getTotalPrice(){//计算订单的总价
        
        int sum = 0;int i = 0 ;
        for(i = 0; i < records.size();i++){
            sum += records.get(i).getPrice();
        }
        return sum;
    }
    
    public void addARecord(int orderNum,String dishName,int portion,int num){//添加一条菜品信息
        
        records.get(RecordNum).setOrderNum(orderNum);
        records.get(RecordNum).getD().setName(dishName);
        records.get(RecordNum).setPortion(portion);
        records.get(RecordNum).setNum(num);
        RecordNum++;
    }
    public void delARecordByOrderNum(int orderNum){//根据序号删除一条记录
        for(int i = 0; i < records.size(); i++) {
            if(records.get(i).getOrderNum() == orderNum) {
                records.remove(i);
            }
        }
    }
    public Record findRecordByNUm(int orderNum){////根据序号查找一条记录
       for(int i = 0 ; i < records.size() ; i++) {
           if(records.get(i).getOrderNum() == orderNum) {
               return records.get(i);
           }
           
       }
    return null;
    }
 }
View Code

运行结果如上图:

只有一两个测试点对了,导致这个题目几乎没有分。

一开始写的时候,我是想着先写完后面具体的类的具体方法,最后再来写main类中的具体的逻辑。我的思路是先一行行得输入,遇到这个字符串为“end”时,就结束输入的循环,然后进行判断的操作:

若第一个字符不是t,则该行为菜单,菜单包含很多条菜;如果按空格切开来为2个,则为普通菜;如果切开来为3个,则为特殊菜。然后继续循环判断下一条字符串。如果字符串第一个字符为t,则跳出之前的循环,进入一个新的循环,之前的字符串都判定为菜单字符串;在新循环里,若该行第一个字符是t,则该行是桌号标识字符串,存在做好标识数组中;若该行不含delete且切开来是四个,则该行是点菜信息;若该行含有delete,且切开来是两行,则该行是删除记录,删除相应的菜谱信息;若该行含有“table”且切开来为6行,则该字符串为代点菜信息。如此循环,直到该字符串为end.

这个题目只有两个异常情况对了,正常的情况一个都没对;这还是因为我对类与类之间的关系还不够熟悉,再加上题目有一定难度,并且其他同学不想写的呼声很大,包括我自己也偷懒,写到一半就半途而废,所以这道题的分数就很低。

相应的类图如下:

 

 

三.踩坑心得

1.在写去除重复的数据这个题目的时候,我的源码如下:

 

用的是后接法,把有重复的数据变成0,然后再输出不含0的项就行了,但是这个方法再N很大的时候就不行了,会运行超时。

 

 于是我就用了hashset和linkedhashset来避免有重复的数据,这样就不会出现N很大会运行超时的情况。

2.在写单词统计与排序这道题的时候,我一开始想着直接按照空格,逗号,句号来切割字符串:

结果发现它并不会直接按照这些切割成一个个单词,而是返回空指针;后面我就转变了思路,先切割空格,再看切割出的单词是否含有句号或者逗号,然后删掉逗号和句号,最后按照单词的长度和大小来进行排序(可能是我正则表达式用的有问题),最后才得到正确答案。

 3.在写日期问题面向对象设计的题目时,在DateUtil调用Month,Day和Year对象的时候,我一开始写的是date.day.month.year.getValue();导致运行的时候都是错误,后面问了同学才知道。每个类里的get方法可以返回该类含有的对象,于是将代码改为date.getDay().getMonth().getYear().getValue();这样就可以一直调用了。

四.改进建议

1.在写题目集四的判断两个日期之间的天数的时候,我的输出的函数如下:

一个是前面的日期更大的情况,另一个是前面的天数更小的情况。两个输出都有相同的部分,可以改成先根据日期的大小,判断两日期之间的天数是正数还是负数,对两个日期的天数进行处理 ,然后在进行输出,这样就不会有重复的代码。

 2.题目集5的7-5判断日期是否合理的方法:

我是先判断年是否合理,再判断月份是否合理,最后再判断天数是否合理,后续可以改成if(day.getMonth().getYear()).validate() && day.getMonth().validate() && day.validate())直接判断三个值是否合法,否则返回false;这样比之前的更简洁,也不容易搞混括号的范围。

在求下N天的方法时

 1  public DateUtil getNextNDays(int n){
 2          for( ; n > 0 ; n--){
 3             if(month.getValue() != 12) {//不是12月
 4                 if(month.getValue() == 2){//二月
 5                     if(year.isLeapYear()){
 6                         if(day.getValue() != 29)
 7                             day.dayIncrement();
 8                         else{
 9                             setDayMin();
10                             month.monthIncrement();
11                         
12                         }
13                     }
14                     else{//不是闰年
15                         if(day.getValue() != 28)
16                             day.dayIncrement();
17                         else{
18                             setDayMin();
19                             month.monthIncrement();
20                         }
21                     }
22                 }//2月
23                 else{//不是二月
24                     if(month.getValue() == 1 || month.getValue() == 3 || month.getValue() == 5 || month.getValue() == 7 || month.getValue() == 8 || month.getValue() == 10){
25                         if(day.getValue() != 31)
26                             day.dayIncrement();
27                         else{
28                             this.setDayMin();
29                             month.monthIncrement();
30                         }
31                             
32                     }
33                     else {
34                         if(day.getValue() != 30)
35                             day.dayIncrement();
36                         else{
37                             this.setDayMin();
38                             month.monthIncrement();
39                 
40                         }
41                     }
42       
43                 }
44             }
45             else{ //是12月
46                 if(day.getValue() != 31)
47                     day.dayIncrement();
48                 else{
49                     this.setDayMin();
50                     month.resetMin();
51                     year.yearIncrement();
52                 }
53             }
54                
55         }//n
56         DateUtil newDate = new DateUtil(day.getValue(),month.getValue(),year.getValue());
57         return newDate;
58     }
View Code

我没次都是判断最后的日期不是临界值的时候,就让day++;后续可以改成一开始就让day++,再判断是否为临界值,如果是临界值的话,就让day等于1,然后月份和年也做相应的变换,这样可以节省很多行的 day.dayIncrement();节省空间。

 

五.总结

1.首先,通过这几次作业,我已经对类与对象的关系有了基本了解,类与类之间的关系有关联,依赖,聚合等,类可以实例化一个或多个对象,一个类中可以含有另一个类的对象,这样就形成了聚合关系。

2.题目集4的7-3去除重复数据,我知道了有LinkedHashSet这个工具,可以让存储的数据不重复,并且保持输入顺序的不变性,这在很多情况下就可以不用进行删除的步骤。

3.题目集4的最后一题,我知道了有关时间的很多方法,LocalDate类中比较两个日期之间的天数,返回的是相差的天数,有正也有负。

4.题目集5主要考察了正则表达式的使用,正则表达式是符合某种规则的字符串,只要满足这种规则的字符串就会返回true,利用这个可以检验QQ号,账号名,学号,验证码等有一定规律的字符串。

5.题目集5的日期类问题,我了解了类与类之间的关系,以及如何正确地设计类与类之间的关系。一个类可以包含另一个类中的对象,比如DateUtil类中含有Day类,Day类中含有Month类,Month类中含有Year类,它们之间的关系为聚集。

 



 
 
 
posted @ 2023-04-30 21:13  辰海  阅读(44)  评论(0编辑  收藏  举报