Java第二次作业总结
一、前言
开头容我吐槽一下啊,这一次三个题目集相比于上次来说难度有点高呀,本来是上一次的每个题目集拿个满分还比较容易,而现在这三个题目集一个满分都没有,更有第六次题目集中的没及格,讲道理这内心落差有点大,尤其是看到测试点没过后测试无数个样例依旧找不出错误的血压飙升,电脑面前双手合十后祈祷无果真的头痛,先简单地分析一波这次作业的情况:能力不够牛,时间不够多,血压不够低。
OOP训练集04涉及知识点:
类与类的关系,类的设计,集合(Hashset),迭代器(iterator),字符串分割,Collections类 ,封装性,LocalDate类,ChronoUnit类
题量:
1.菜单计价程序-3(万恶之源)
2.有重复的数据
3.去掉重复的数据
4.单词统计与排序
5.面向对象编程(封装性)
6.GPS测绘中度分秒转换
7.判断两个日期的先后,计算间隔天数、周数
一共7道题,题目量还行,中规中矩。
难度:
除了第一道的菜单,其他题目难度不高,但一道菜单题足以拉高整个题目集难度系数很多
OOP训练集05
涉及知识点:
正则表达式,字符串排序,面向对象设计,聚合
题量:
1.正则表达式训练-QQ号校验
2.字符串训练-字符排序
3.正则表达式训练-验证码校验
4.正则表达式训练-学号校验
5.日期问题面向对象设计(聚合一)
6.日期问题面向对象设计(聚合二)
一共6道题,题量不多,且后面两道的虽然代码量比较多,但也只是前面题目基础上加了一点东西。
难度:
难度不高,正则表达式理解起来也比较容易,第2题有点凑数的感觉,后面两道题有前面的基础,改起来也不难,但老是有个别测试点通过不了又找不出来就很难受。
OOP训练集06
涉及知识点:
ChronoField类,LocalDate类,字符串分割,类的设计
题量:
1.菜单计价程序-4
虽然只有一道题,看这一道100分的题就知道其分量了,代码量超多,光看题目都要看很久,可以说一道更比七道强。
难度:
难度很高,题目理解难度有点高,题目给的要求也非常多,简单来说就是又难又麻烦
二、设计与分析
这次分析主要还是对日期类和菜单进行分析,其他题目很多都在菜单题中有所体现,还有正则表达式内容很少,所以其他题目就不做过多赘述了。
由于训练集04和06都是菜单题,因此我先对训练集05中的日期问题进行分析。
OOP训练集05
7-5 日期问题面向对象设计(聚合一)
先看代码和类图:
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.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.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 Year{ private int value; public Year(){ value = 0; } 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--; } } class Month{ private int value; private Year year; public Month() { value = 0; year = new Year(); } public Month(int yearvalue,int monthvalue) { this.value = monthvalue; this.year = new Year(yearvalue); } public int getValue() { return value; } public void setValue(int value) { this.value = value; } public Year getYear() { return year; } 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 Day{ private int value; private Month month; private int[] mon_maxnum = new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31}; public Day() { value = 0; month = new Month(); } public Day(int yearvalue, int monthvalue, int dayvalue) { this.value = dayvalue; this.month = new Month(yearvalue, monthvalue); if(month.getYear().isLeapYear()) mon_maxnum[2] = 29; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } public Month getMonth() { return month; } public int getMon_maxnum() { return mon_maxnum[month.getValue()]; } public void setYear(Month month) { this.month = month; } public void resetMin() { if(month.getYear().isLeapYear()) mon_maxnum[2] = 29; else mon_maxnum[2] = 28; value = 1; } public void resetMax() { if(month.getYear().isLeapYear()) mon_maxnum[2] = 29; else mon_maxnum[2] = 28; value = mon_maxnum[month.getValue()]; } public boolean validate() { if(!month.validate()) 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 DateUtil{ private Day day; public DateUtil(){ day = new Day(); } public DateUtil(int y, int m, int d){ day = new Day(y, m, d); } public Day getDay() { return day; } public void setDay(Day d) { day = d; } public boolean checkInputValidity() { if(day.validate() && day.getMonth().validate() && day.getMonth().getYear().validate()) return true; else return false; } public boolean compareDates(DateUtil date){ if(day.getMonth().getYear().getValue() < date.getDay().getMonth().getYear().getValue()) return true; else if(day.getMonth().getYear().getValue() == date.getDay().getMonth().getYear().getValue()) { if(day.getMonth().getValue() < date.getDay().getMonth().getValue()) return true; else if(day.getMonth().getValue() == date.getDay().getMonth().getValue()){ if(day.getValue() < date.getDay().getValue()) return true; else return false; } else return false; } else return false; } public boolean equalTwoDates(DateUtil date){ if(day.equals(date)) return true; else return false; } public String showDate(){ return day.getMonth().getYear().getValue()+"-"+day.getMonth().getValue()+"-"+day.getValue(); } public DateUtil getNextNDays(int n) { while(n > day.getMon_maxnum() - day.getValue() ){ if(day.getMonth().getValue() == 12){ n = n - day.getMon_maxnum() + day.getValue(); day.resetMin(); day.getMonth().resetMin(); day.getMonth().getYear().yearIncrement(); } else{ n = n - day.getMon_maxnum() + day.getValue(); day.resetMin(); day.getMonth().monthIncrement(); } n--; } for(int i = 0; i < n; i++) day.dayIncrement(); DateUtil d =new DateUtil(); d.setDay(day); return d; } public DateUtil getPreviousNDays(int n){ if(day.getValue() <= n){ n = n - day.getValue(); if(day.getMonth().getValue() == 1){ day.getMonth().getYear().yearReduction(); day.getMonth().resetMax(); day.resetMax(); } else{ day.getMonth().monthReduction(); day.resetMax(); } } while(day.getValue() <= n){ n = n - day.getMon_maxnum(); if(day.getMonth().getValue() == 1){ day.getMonth().getYear().yearReduction(); day.getMonth().resetMax(); day.resetMax(); } else{ day.getMonth().monthReduction(); day.resetMax(); } } for(int i = 0; i < n; i++) day.dayReduction(); DateUtil d =new DateUtil(); d.setDay(day); return d; } public int getDaysofDates(DateUtil date){ int today = date.getDay().getValue(); int n = 0; while(compareDates(date)){ if(equalTwoDates(date)){ break; } else{ if(day.getMonth().getYear().getValue() == date.getDay().getMonth().getYear().getValue() && day.getMonth().getValue() == date.getDay().getMonth().getValue()){ n = n + today - day.getValue(); day.setValue(today); } else if(day.getMonth().getValue() == 12){ n = n + day.getMon_maxnum() - day.getValue() + 1; day.resetMin(); day.getMonth().resetMin(); day.getMonth().getYear().yearIncrement(); } else{ n = n + day.getMon_maxnum() - day.getValue() + 1; day.resetMin(); day.getMonth().monthIncrement(); } } } return n; } }
老师给的:
我自己的:
这次日期问题相比于上次,就是将日期中年月日单独拆分成三个类,日期算法方面与之前没有多大区别,需要稍微进行改进,就比如我在Day里加入一个获取月份最大的get方法,还有在每次天数加1时判断闰年来改变每月最大天数数组中2月的最大天数等。而这次也用到了类与类之间关系设计中的聚合关系,就有点像套娃一样,一环接一环。DateUtil->Day->Month->Year,由于聚合关系,Day,Month,Year三个类都绑在一起,可以很好地理解,在对日期进行操作是需要一层一层递进,调用方法时需要一级一级调用,保证封装性的同时也可以提高代码的复用性。
7-6 日期问题面向对象设计(聚合二)
先看代码和类图:
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.getYear().getValue() + "-" + date.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.getYear().getValue() + "-" + date.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("The days between " + fromDate.showDate() + " and " + toDate.showDate() + " are:" + fromDate.getDaysofDates(toDate)); } else { System.out.println("Wrong Format"); System.exit(0); } } else{ System.out.println("Wrong Format"); System.exit(0); } } } class Year{ private int value; public Year(){ value = 0; } 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 >= 1820 && value <= 2020) return true; else return false; } public void yearIncrement() { value++; } public void yearReduction() { value--; } } class Month{ private int value; public Month() { value = 0; } public Month(int value) { this.value = value; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } 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 Day{ private int value; public Day() { value = 0; } public Day(int value) { this.value = value; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } public void dayIncrement() { value++; } public void dayReduction() { value--; } } class DateUtil{ private Year year; private Month month; private Day day; private int[] mon_maxnum = new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31}; public DateUtil(){ year = new Year(); month = new Month(); day = new Day(); } public DateUtil(int y, int m, int d){ year = new Year(y); month = new Month(m); day = new Day(d); if(year.isLeapYear()) mon_maxnum[2] = 29; } public Year getYear() { return year; } public void setYear(Year y) { year = y; } public Month getMonth() { return month; } public void setMonth(Month m) { month = m; } public Day getDay() { return day; } public void setDay(Day d) { day = d; } public void resetMin() { if(year.isLeapYear()) mon_maxnum[2] = 29; else mon_maxnum[2] = 28; day.setValue(1); } public void resetMax() { if(year.isLeapYear()) mon_maxnum[2] = 29; else mon_maxnum[2] = 28; day.setValue(mon_maxnum[month.getValue()]); } public boolean checkInputValidity() { if(month.validate() && year.validate()) { if(day.getValue() >= 1 && day.getValue() <= mon_maxnum[month.getValue()]) return true; else return false; } else return false; } public boolean compareDates(DateUtil date){ if(year.getValue() < date.getYear().getValue()) return true; else if(year.getValue() == date.getYear().getValue()) { if(month.getValue() < date.getMonth().getValue()) return true; else if(month.getValue() == date.getMonth().getValue()){ if(day.getValue() < date.getDay().getValue()) return true; else return false; } else return false; } else return false; } public boolean equalTwoDates(DateUtil date){ if(day.equals(date)) return true; else return false; } public String showDate(){ return year.getValue()+"-"+month.getValue()+"-"+day.getValue(); } public DateUtil getNextNDays(int n) { while(n > mon_maxnum[month.getValue()] - day.getValue() ){ if(month.getValue() == 12){ n = n - mon_maxnum[month.getValue()] + day.getValue(); resetMin(); month.resetMin(); year.yearIncrement(); } else{ n = n - mon_maxnum[month.getValue()] + day.getValue(); resetMin(); month.monthIncrement(); } n--; } for(int i = 0; i < n; i++) day.dayIncrement(); DateUtil d =new DateUtil(year.getValue(),month.getValue(),day.getValue()); return d; } public DateUtil getPreviousNDays(int n){ if(day.getValue() <= n){ n = n - day.getValue(); month.monthReduction(); resetMax(); } while(day.getValue() <= n){ if(month.getValue() == 1){ n = n - mon_maxnum[month.getValue()]; year.yearReduction(); month.resetMax(); resetMax(); } else{ n = n - mon_maxnum[month.getValue()]; month.monthReduction(); resetMax(); } } for(int i = 0; i < n; i++) day.dayReduction(); DateUtil d =new DateUtil(year.getValue(),month.getValue(),day.getValue()); return d; } public int getDaysofDates(DateUtil date){ int today = date.getDay().getValue(); int n = 0; while(compareDates(date)){ if(equalTwoDates(date)){ break; } else{ if(year.getValue() == date.getYear().getValue() && month.getValue() == date.getMonth().getValue()){ n = n + today - day.getValue(); day.setValue(today); } else if(month.getValue() == 12){ n = n + mon_maxnum[month.getValue()] - day.getValue() + 1; resetMin(); month.resetMin(); year.yearIncrement(); } else{ n = n + mon_maxnum[month.getValue()] - day.getValue() + 1; resetMin(); month.monthIncrement(); } } } return n; } }
老师给的:
我自己的:
这道题和上一道题类似,只是换了一种聚合方式,Day,Month,Year三个类之间没有关联,而是都与DateUtil聚合,因此在调用方法时没有像上一题的需要层层递进,更为简单直接。总体上代码复用性那么高,但是在主方法部分也不用套娃一样写一大串。
OOP训练集04
7-1 菜单计价程序-3
先看代码和类图:
import java.time.LocalDate; import java.time.LocalTime; import java.time.temporal.ChronoField; import java.util.Scanner; public class Main { public static void main(String[] args) { @SuppressWarnings("resource") Scanner in = new Scanner(System.in); Dish[] dish = new Dish[2]; String[] dish1 = in.nextLine().split(" "); dish[0] = new Dish(dish1[0],Integer.parseInt(dish1[1])); String[] dish2 = in.nextLine().split(" "); dish[1] = new Dish(dish2[0],Integer.parseInt(dish2[1])); Menu menu = new Menu(dish); String[] num = in.nextLine().split(" "); Record[] records = new Record[2]; String[] record1 = in.nextLine().split(" "); records[0] = new Record(Integer.parseInt(record1[0]),dish[0],Integer.parseInt(record1[2]),Integer.parseInt(record1[3])); String[] record2 = in.nextLine().split(" "); records[1] = new Record(Integer.parseInt(record2[0]),dish[1],Integer.parseInt(record2[2]),Integer.parseInt(record2[3])); System.out.println(num[0]+" "+num[1]+": "); System.out.println(records[0].getOrderNum()+" "+records[0].getDish().getName()+" "+records[0].getPrice()); System.out.println(records[1].getOrderNum()+" "+records[1].getDish().getName()+" "+records[1].getPrice()); int judge = IsOpeningHours(getWeek(num[2]),getTime(num[3])); Order order = new Order(records,menu); String end = in.nextLine(); while(!end.equals("end")) { String[] delete = end.split(" "); int a = Integer.parseInt(delete[0]); order.delARecordByOrderNum(a); end = in.nextLine(); } double total = 0; if(judge == -1) System.out.println(num[0]+" "+num[1]+"out of opening hours"); else { total = order.getTotalPrice()*0.1*judge; if(total - (int)total >= 0.5) total = (int)total + 1; else total = (int)total; System.out.println(num[0]+" "+num[1]+": "+(int)total); } } public static int getWeek(String date) { String[] DATE = date.split("/"); LocalDate Date = LocalDate.of(Integer.parseInt(DATE[0]),Integer.parseInt(DATE[1]),Integer.parseInt(DATE[2])); return Date.get(ChronoField.DAY_OF_WEEK); } public static LocalTime getTime(String time) { String[] TIME = time.split("/"); LocalTime Time = LocalTime.of(Integer.parseInt(TIME[0]),Integer.parseInt(TIME[1]),Integer.parseInt(TIME[2])); return Time; } public static int IsOpeningHours(int week,LocalTime time) { if(week <= 5) { if(time.isAfter(LocalTime.of(16,59,59))&&time.isBefore(LocalTime.of(20,30,1))) return 8; else if(time.isAfter(LocalTime.of(10,29,59))&&time.isBefore(LocalTime.of(14,30,1))) return 6; else return -1; } else { if(time.isAfter(LocalTime.of(9,30,0))&&time.isBefore(LocalTime.of(21,30,0))) return 10; else return -1; } } } class Dish{ private String name; private int util_price; public Dish() { name = ""; util_price = 0; } public Dish(String name,int util_price){ this.name = name; this.util_price = util_price; } public String getName() { return name; } public int getPrice(int portion){ double price = 0; switch(portion){ case 1:{ price = util_price; break; } case 2:{ price = util_price * 1.5; break; } case 3:{ price = util_price * 2; break; } } if(price - (int)price >= 0.5) return (int)price + 1; else return (int)price; } } class Menu{ private Dish[] dishs; public Menu(Dish[] dishs) { this.dishs = new Dish[dishs.length]; for(int i = 0; i < dishs.length; i++) { this.dishs[i] = dishs[i]; } } public Dish searthDish(String dishName) { int num = 0; Dish flag = new Dish(); for(int i = 0; i < dishs.length; i++) { if(dishs[i].getName().equals(dishName)) { num = i; flag = new Dish("1",0); } } if(flag.getName().equals("1")) return dishs[num]; else return flag; } public Dish addDish(String dishName,int unit_price) { return new Dish(dishName,unit_price); } } class Record{ private int orderNum; private Dish d; private int portion; private int num; public Record() { orderNum = 0; d = new Dish(); portion = 0; num = 0; } public Record(int orderNum,Dish d,int portion,int num) { this.orderNum = orderNum; this.d = d; this.portion = portion; this.num = num; } public int getOrderNum(){ return orderNum; } public Dish getDish() { return d; } public int getPrice() { return d.getPrice(portion)*num; } } class Order{ private Record[] records; private Menu menu; public Order(Record[] records,Menu menu) { this.records = new Record[records.length]; for(int i = 0; i < records.length; i++) this.records[i] = records[i]; this.menu = menu; } public int getTotalPrice() { int TotalPrice = 0; for(int i = 0; i < records.length; i++) { TotalPrice += records[i].getPrice(); } return TotalPrice; } public Record addARecord(int orderNum,String dishName,int portion,int num) { Dish d = menu.searthDish(dishName); Record error = new Record(); if(d.getName().equals("")) return error; else return new Record(orderNum,d,portion,num); } public void delARecordByOrderNum(int orderNum) { int flag = 0; for(int i = 0; i < records.length; i++) { if(findRecordByNum(orderNum)) { records[i] = new Record(); flag = 1; } } if(flag == 0) System.out.println("delete error;"); } public boolean findRecordByNum(int orderNum) { for(int i = 0; i < records.length; i++) { if(records[i].getOrderNum() == orderNum) { return true; } } return false; } }
类图:
由于做这个训练集时时间有点紧张,所以这道题的完成度非常低,很多要求都没有实现,基本只是把类给设计好了,点菜和统计价格,同时用到了LocalDate和LocalTime,还有ChronoField来判断营业时间。字符串分割在这题出现频率很高,基本输入的每一句都要靠分割后的字符串数组来输入数据。因此输入也是一个很棘手的难点。但是其实有很多问题还是在第二次菜单中得到解决,因此大部分分析还是在下面来分析吧。
OOP训练集06
7-1 菜单计价程序-4
import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.LocalTime; import java.time.temporal.ChronoField; import java.util.Scanner; public class Main { public static void main(String[] args) { @SuppressWarnings("resource") Scanner in = new Scanner(System.in); Dish[] dish = new Dish[10]; String[] command = in.nextLine().split(" "); for(int i = 0; !command[0].equals("table"); i++) { if(isNumeric(command[1])) { if(command.length > 2) { if(command.length < 4) dish[i] = new Dish(command[0],Integer.parseInt(command[1]),true); else { System.out.println("wrong format"); System.exit(0); } } else dish[i] = new Dish(command[0],Integer.parseInt(command[1]),false); if(!(dish[i].getUtilPrice() > 0&&dish[i].getUtilPrice() < 300)) { System.out.println(dish[i].getName()+" price out of range "+dish[i].getUtilPrice()); dish[i] = new Dish(); } } else { dish[i] = new Dish(); System.out.println("wrong format"); } command = in.nextLine().split(" "); } Menu menu = new Menu(dish); if(isTable(command)) { Table[] table = new Table[10]; int tableNum =0; for(tableNum = 0; command[0].equals("table"); tableNum++) { table[tableNum] = new Table(Integer.parseInt(command[1]),command[2],command[3]); System.out.println("table "+table[tableNum].getNum()+": "); Record[] records = new Record[10]; command = in.nextLine().split(" "); for(int j = 0; !(command[1].equals("delete")||isTable(command)); j++) { if(command[0].length() > 2) { if(command.length > 3) records[j] = new Record(1,new Dish(),0,0); else System.out.println("invalid dish"); } else { if(menu.searthDish(command[1]).getName().equals("notexist")) { System.out.println(command[1]+" does not exist"); records[j] = new Record(); } else { records[j] = new Record(Integer.parseInt(command[0]),menu.searthDish(command[1]),Integer.parseInt(command[2]),Integer.parseInt(command[3])); } } command = in.nextLine().split(" "); if(command[0].equals("end")) break; } Order order = new Order(records,menu); table[tableNum].setOrder(order); order.showOrder(); if(!command[0].equals("end")) { while(command[1].equals("delete")) { order.delARecordByOrderNum(Integer.parseInt(command[0])); command = in.nextLine().split(" "); if(command[0].equals("end")) break; } } } for(int i = 0; i < tableNum; i++) { table[i].showTotal(); } } else System.out.println("wrong format"); } public static boolean isTable(String[] table ) { if(table.length < 5) { if(table[0].equals("table")) { if(isNumeric(table[1])) { if(table[3].length() == 8) return true; else return false; } else return false; } else return false; } else return false; } public static boolean isNumeric(String str) { if (str == null) { return false; } int sz = str.length(); for (int i = 0; i < sz; i++) { if (Character.isDigit(str.charAt(i)) == false) { return false; } } return true; } } class Dish{ private String name; private int util_price; private boolean t; public Dish() { name = ""; util_price = 0; t = false; } public Dish(String name,int util_price,boolean t){ this.name = name; this.util_price = util_price; this.t = t; } public String getName() { return name; } public int getUtilPrice() { return util_price; } public boolean getT() { return t; } public int getPrice(int portion){ double price = 0; switch(portion){ case 1:{ price = util_price; break; } case 2:{ price = util_price * 1.5; break; } case 3:{ price = util_price * 2; break; } } if(price - (int)price >= 0.5) return (int)price + 1; else return (int)price; } } class Menu{ private Dish[] dishs; public Menu(Dish[] dishs) { this.dishs = new Dish[dishs.length]; for(int i = 0; i < dishs.length; i++) { if(dishs[i] == null) this.dishs[i] = new Dish(); else this.dishs[i] = dishs[i]; } } public Dish searthDish(String dishName) { int num = 0; Dish flag = new Dish("notexist",0,false); for(int i = 0; i < dishs.length; i++) { if(dishs[i].getName().equals(dishName)) { num = i; flag = new Dish("exist",0,false); } } if(flag.getName().equals("exist")) return dishs[num]; else return flag; } public Dish addDish(String dishName,int unit_price,boolean t) { return new Dish(dishName,unit_price,t); } } class Record{ private int orderNum; private Dish d; private int portion; private int num; public Record() { orderNum = 0; d = new Dish(); portion = 0; num = 0; } public Record(int orderNum,Dish d,int portion,int num) { this.orderNum = orderNum; this.d = d; this.portion = portion; this.num = num; } public int getOrderNum(){ return orderNum; } public Dish getDish() { return d; } public int getPortion() { return portion; } public int getNum() { return num; } public int getPrice() { if(!d.getT()&&(portion < 0||portion > 3)) return 0; else if(d.getT()&&(portion < 0||portion > 3)) return 0; else { if(num > 15) return 0; else return d.getPrice(portion)*num; } } public void Priceshow() { if(portion < 10) { if(!d.getT()&&(portion < 0||portion > 3)) System.out.println(orderNum+" num out of range "+portion); else if(d.getT()&&(portion < 0||portion > 3)) System.out.println(orderNum+" portion out of range "+portion); else { if(num > 15) System.out.println(orderNum+" num out of range "+num); else System.out.println(orderNum+" "+d.getName()+" "+getPrice()); } } else System.out.println("wrong format"); } } class Order{ private Record[] records; private Menu menu; public Order(Record[] records,Menu menu) { this.records = new Record[records.length]; for(int i = 0; i < records.length; i++) if(records[i] == null) this.records[i] = new Record(); else this.records[i] = records[i]; this.menu = menu; } public Record[] getRecords() { return records; } public int getTotalPrice() { int TotalPrice = 0; for(int i = 0; i < records.length; i++) { TotalPrice += records[i].getPrice(); } return TotalPrice; } public Record addARecord(int orderNum,String dishName,int portion,int num) { Dish d = menu.searthDish(dishName); Record error = new Record(); if(d.getName().equals("")) return error; else return new Record(orderNum,d,portion,num); } public void delARecordByOrderNum(int orderNum) { int flag = findRecordByNum(orderNum); if(flag != -1) { if(records[flag].getNum() == 0) System.out.println("deduplication "+ orderNum); records[flag] = new Record(orderNum,new Dish(),0,0); } else System.out.println("delete error"); } public int findRecordByNum(int orderNum) { for(int i = 0; i < records.length; i++) { if(records[i].getOrderNum() == orderNum) { return i; } } return -1; } public void showOrder() { for(int i = 0; i < records.length; i++) { if(records[i].getNum() != 0) { int m = i; for(m = i; m > 0; m--) { if(records[m-1].getOrderNum() >= records[i].getOrderNum()) { System.out.println("record serial number sequence error"); records[i] = new Record(); break; } } if(m == 0) records[i].Priceshow(); } else { if(records[i].getOrderNum() == 1) System.out.println("wrong format"); } } } } class Table { private int num; private Order order; private LocalDate date; private LocalTime time; private double total; public Table(int num,String date,String time) { this.num = num; if(check(date)) { String[] DATE = date.split("/"); this.date = LocalDate.of(Integer.parseInt(DATE[0]),Integer.parseInt(DATE[1]),Integer.parseInt(DATE[2])); } else this.date = LocalDate.of(1,1,1); String[] TIME = time.split("/"); this.time = LocalTime.of(Integer.parseInt(TIME[0]),Integer.parseInt(TIME[1]),Integer.parseInt(TIME[2])); this.total = 0.0; } public void setOrder(Order order) { this.order = order; } public int getNum() { return num; } public Order getOrder() { return order; } public LocalDate getDate() { return date; } public LocalTime getTime() { return time; } public double getTotal() { return total; } public int getWeek() { return date.get(ChronoField.DAY_OF_WEEK); } public int OpeningHours(int week,LocalTime time,boolean T) { if(week <= 5) { if(T) { return 7; } else { if(time.isAfter(LocalTime.of(16,59,59))&&time.isBefore(LocalTime.of(20,30,1))) return 8; else if(time.isAfter(LocalTime.of(10,29,59))&&time.isBefore(LocalTime.of(14,30,1))) return 6; else return -1; } } else { if(time.isAfter(LocalTime.of(9,30,0))&&time.isBefore(LocalTime.of(21,30,0))) return 10; else return -1; } } public int getDiscountedPrice() { int discountedPrice = 0; Record[] records = order.getRecords(); double[] price = new double[records.length]; for(int i = 0; i < records.length; i++) { price[i] = records[i].getPrice()*OpeningHours(getWeek(),getTime(),records[i].getDish().getT())*0.1; if(price[i] - (int)price[i] >= 0.5) price[i] = (int)price[i] + 1; else price[i] = (int)price[i]; } for(int i = 0; i < price.length; i++) discountedPrice += (int)price[i]; return discountedPrice; } public void showTotal() { int judge = OpeningHours(getWeek(),getTime(),false); if(judge == -1) System.out.println("table"+" "+num+"out of opening hours"); else { if(date.isAfter(LocalDate.of(2020,1,1))&&date.isBefore(LocalDate.of(2023,12,31))) System.out.println("table"+" "+num+": "+order.getTotalPrice()+" "+getDiscountedPrice()); else System.out.println("not a valid time period"); } } public static boolean check (String str) { SimpleDateFormat sd = new SimpleDateFormat("yyyy/MM/dd"); try { sd.setLenient(false); sd.parse(str); } catch (Exception e) { return false; } return true; } }
类图:
这次菜单相比于上次有了很大的完善,虽然还是有比较多的要求没实现,功能也还算比较齐全,完成度还可以。这次是上次的加强版,加了一些新功能和一堆异常判断,PTA中测试点也是围绕异常来进行评测得分的。首当其冲的便是头疼的信息输入问题得到解决,通过字符串分割后数组中的一些特殊信息来相对准确的对号入座,循环也是借此来输入多条类似信息,保证信息能够准确的输入。如isTable方法就是用来判断该条信息数组中的一个是否为table,判断桌号是否是数字和桌号时间是合法。先创建table对象数组,再创建dish对象数组代表菜单的菜品,输入完再加入到menu对象中,创建record对象数组代表点菜记录,循环输入完后加入order对象中,最后循环结束时再加入table对象中。各种异常也需要同时考虑到还有每条异常优先级。
三、踩坑心得
回顾来看的话很多地方其实解决方案其实很简单,我这次就专门拿出一些我比较头疼的问题来讲一下。
7-4 单词统计与排序
这道题的要求非常的麻烦,涉及到字符串分割,还有排序
一般Java自带的排序的方法一般是按首字母来排序的,而这种排序方法是区分大小写的也就是根据ASCII码-来排序,这显然不能达到题目要求,不仅要不分大小写还要长度来升序输出,如果自己写方法的话会很麻烦而且容易导致运行超时。
先将分割后单词放进ArrayList数值中;
利用Collections对单词进行不分大小写的排序;
再对单词长度进行排序。
7-1 菜单计价程序
开始写这道题时,当设计完所有类时发现输入是个大问题,怎样输入多条不固定的信息,并能准确找到对应需要的信息成了大问题,更何况各种麻烦的异常判断。
在第一次接触菜单题时,为了应付部分测试点而只是固定输入信息的条数
毫无疑问这完全不能解决问题,只是时间来不及的无奈之举,后来在写的时候发现可以循环利用输入语句中的特殊字符来结束循环来达到输入不固定数量的语句,end语句结束输入中有用到
所以在下一次菜单题中这种方式得以解决困扰很久的输入问题,同时根据题目要求用到了嵌套双重循环,包含很多if-else语句来解决异常
String[] command = in.nextLine().split(" "); for(int i = 0; !command[0].equals("table"); i++) { if(isNumeric(command[1])) { if(command.length > 2) { if(command.length < 4) dish[i] = new Dish(command[0],Integer.parseInt(command[1]),true); else { System.out.println("wrong format"); System.exit(0); } } else dish[i] = new Dish(command[0],Integer.parseInt(command[1]),false); if(!(dish[i].getUtilPrice() > 0&&dish[i].getUtilPrice() < 300)) { System.out.println(dish[i].getName()+" price out of range "+dish[i].getUtilPrice()); dish[i] = new Dish(); } } else { dish[i] = new Dish(); System.out.println("wrong format"); } command = in.nextLine().split(" "); } Menu menu = new Menu(dish); if(isTable(command)) { Table[] table = new Table[10]; int tableNum =0; for(tableNum = 0; command[0].equals("table"); tableNum++) { table[tableNum] = new Table(Integer.parseInt(command[1]),command[2],command[3]); System.out.println("table "+table[tableNum].getNum()+": "); Record[] records = new Record[10]; command = in.nextLine().split(" "); for(int j = 0; !(command[1].equals("delete")||isTable(command)); j++) { if(command[0].length() > 2) { if(command.length > 3) records[j] = new Record(1,new Dish(),0,0); else System.out.println("invalid dish"); } else { if(menu.searthDish(command[1]).getName().equals("notexist")) { System.out.println(command[1]+" does not exist"); records[j] = new Record(); } else { records[j] = new Record(Integer.parseInt(command[0]),menu.searthDish(command[1]),Integer.parseInt(command[2]),Integer.parseInt(command[3])); } } command = in.nextLine().split(" "); if(command[0].equals("end")) break; } Order order = new Order(records,menu); table[tableNum].setOrder(order); order.showOrder(); if(!command[0].equals("end")) { while(command[1].equals("delete")) { order.delARecordByOrderNum(Integer.parseInt(command[0])); command = in.nextLine().split(" "); if(command[0].equals("end")) break; } } } for(int i = 0; i < tableNum; i++) { table[i].showTotal(); } } else System.out.println("wrong format");
用for循环方便对象数组的操作,因此这样输入问题便迎刃而解了。
四舍五入的顺序也挺让人头疼的,原本时将所有菜品价格都加起来后再四舍五入计算最终价格,不按这步骤得到的误差很大,而且因为在类里面计算价格,所以改起来很麻烦,涉及到多个类的改动,同时需要考虑输出的问题。
Menu类:
public int getPrice(int portion){ double price = 0; switch(portion){ case 1:{ price = util_price; break; } case 2:{ price = util_price * 1.5; break; } case 3:{ price = util_price * 2; break; } } if(price - (int)price >= 0.5) return (int)price + 1; else return (int)price;
Record类:
public int getPrice() { if(!d.getT()&&(portion < 0||portion > 3)) return 0; else if(d.getT()&&(portion < 0||portion > 3)) return 0; else { if(num > 15) return 0; else return d.getPrice(portion)*num; } }
public int getTotalPrice() { int TotalPrice = 0; for(int i = 0; i < records.length; i++) { TotalPrice += records[i].getPrice(); } return TotalPrice; }
Table类:
public int getDiscountedPrice() { int discountedPrice = 0; Record[] records = order.getRecords(); double[] price = new double[records.length]; for(int i = 0; i < records.length; i++) { price[i] = records[i].getPrice()*OpeningHours(getWeek(),getTime(),records[i].getDish().getT())*0.1; if(price[i] - (int)price[i] >= 0.5) price[i] = (int)price[i] + 1; else price[i] = (int)price[i]; } for(int i = 0; i < price.length; i++) discountedPrice += (int)price[i]; return discountedPrice; }
四、改进建议
1.就这次菜单题来看,代码量很大,要求也很多,更加需要我写代码时考虑的更全面,不然后面改起来非常痛苦
2.知识点不够全面,面对一些简单问题总是束手无策,需要更加系统的学习Java,绝对不能马虎
3.时间不够,主要还是自己投入时间不够多,练习太少,处理问题效率低下,需要投入更多时间去锻炼代码能力
五、总结
学到了什么:
1.数组(ArrayList、Collections),集合(Hashset)等
2.类与类之间的关系(聚合)
3.正则表达式
对于教师、课程、作业、实验及课上课下组织方式的改进建议以及意见:
难度曲线可以平缓一点,突然的难度上升会让产生畏惧心理,很容易抵触去尝试,就OOP训练集06班上完成情况就能看出来,很多同学因为难而不知道怎么下手。可以难但可不可以不用难的那么快,凡是都需要一个过程。还有就是老师讲设计模式可以给出更详细的例子,这样就更好理解上手练习。