大作业分析-1
前言:
在前三周的java大作业后下,我主要理解了何为“面向对象”,理解了类,性质和方法的关系,能够较为熟练地使用java,并和“面向过程”区分开来。
但作业写的不够完美。第一次大作业没有完全理解何为“面向对象”,基本还是用c的那一套“面向过程”来写的;第二次大作业仍然不够完全面向过程,但有了一些进展;第三次嗯……对了,但没完全对,总之到现在我也不明白我到底错哪了。总之,慢慢来吧。先来大致分析下三次大作业的题目的知识点、题量、难度等情况。
第一次大作业:
难度较为简单,主要是使用和熟悉Java,出的题目也都是一些基础中的基础题目,重点都不在语法设计而是题目逻辑,也不需要用上各种类。总体来讲是十分简单。
第二次大作业:
本次大作业的餐馆相关题目就主要体现了java的特色“面向对象”,题目对初学者有一定难度。需要彻底理解何为“面向对象”,“面向对象”有什么好处。同时需要花费时间把不同的“类”,“属性”和“方法”划分清楚,才能清楚地做出来这几道题目。
第三次大作业:
先不提餐馆相关题目,本次大作业其他题目主要考察了对java其他方面的要求。例如封装性,各种方法的使用等等。然后就是餐馆相关题目。餐馆题目真是……一言难尽。相比起上次题目提高了一档难度,并且下次还要继续提升。测试点太难改对了,一次又一次的改还是摸不着测试点到底是哪些……咳,总之感觉是最难的一道。但难度不在于如何写,而是如何写对。
下面会细致分析一下我认为比较重点的几道题目。
设计与分析:
第二次餐馆作业:

1 import java.util.Scanner; 2 public class Main { 3 public static void main(String[] args) 4 { 5 int c=0;//判断是否开始订单 6 int d=0;//菜谱的第几道菜 7 int e=0; 8 Scanner in=new Scanner(System.in); 9 Menu menu=new Menu(); 10 Order order=new Order(); 11 while(1>0) 12 { 13 String a=in.nextLine(); 14 if(a.equals("end"))//结束输入循环 15 break; 16 String[] b=a.split(" "); 17 if(b[0].equals("1")) 18 c=1; 19 if(c==0) 20 { 21 menu.dishs[d]=new Dish(); 22 if(menu.searthDish(b[0],d)==null) 23 { 24 menu.dishs[d]=menu.addDish(b[0],Integer.parseInt(b[1])); 25 d++; 26 } 27 else 28 menu.searthDish(b[0],d).unit_price=Integer.parseInt(b[1]); 29 } 30 else 31 { 32 if(menu.searthDish(b[1],d)!=null) 33 { 34 e=Integer.parseInt(b[0]); 35 order.records[Integer.parseInt(b[0])]=new Record(); 36 order.records[Integer.parseInt(b[0])]=order.addARecord(Integer.parseInt(b[0]),menu.searthDish(b[1],d),Integer.parseInt(b[2]),Integer.parseInt(b[3])); 37 System.out.println(order.records[Integer.parseInt(b[0])].orderNum+" "+order.records[Integer.parseInt(b[0])].d.name+" "+order.records[Integer.parseInt(b[0])].getPrice()); 38 } 39 else if(b[1].equals("delete")) 40 { 41 if(Integer.parseInt(b[0])<=e&&Integer.parseInt(b[0])>=1) 42 { 43 if(order.records[Integer.parseInt(b[0])].n==0) 44 order.delARecordByOrderNum(Integer.parseInt(b[0])); 45 else 46 System.out.println("delete error;"); 47 } 48 else 49 System.out.println("delete error;"); 50 } 51 else 52 { 53 e=Integer.parseInt(b[0]); 54 order.records[e]=new Record(); 55 Dish dish=new Dish(); 56 dish.name=b[1].substring(0); 57 dish.unit_price=0; 58 order.records[e]=order.addARecord(e,dish,Integer.parseInt(b[2]),Integer.parseInt(b[3])); 59 System.out.println(b[1]+" does not exist"); 60 } 61 } 62 } 63 System.out.println(order.getTotalPrice(e)); 64 } 65 } 66 //菜品 67 class Dish 68 { 69 String name;//菜品名称 70 int unit_price; //单价 71 int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) 72 { 73 double p=1; 74 switch(portion) 75 { 76 case 1:p=unit_price*1;break; 77 case 2:p=unit_price*1.5;break; 78 case 3:p=unit_price*2;break; 79 } 80 return (int)Math.round(p); 81 } 82 } 83 //菜谱 84 class Menu 85 { 86 Dish[] dishs=new Dish[10] ;//菜品数组,保存所有菜品信息 87 Dish searthDish(String dishName,int d)//根据菜名在菜谱中查找菜品信息,返回Dish对象。 88 { 89 int i; 90 for(i=0;i<d;i++) 91 { 92 if(dishName.equals(dishs[i].name)) 93 return dishs[i]; 94 } 95 return null; 96 } 97 Dish addDish(String dishName,int unit_price)//添加一道菜品信息 98 { 99 Dish dish=new Dish(); 100 dish.name=dishName.substring(0); 101 dish.unit_price=unit_price; 102 return dish; 103 } 104 } 105 //点菜 106 class Record 107 { 108 int orderNum;//序号 109 Dish d;//菜品 110 int portion;//份额(1/2/3代表小/中/大份) 111 int num;//分量 112 int n=0;//标记是否被删除 113 int getPrice()//计价,计算本条记录的价格 114 { 115 double p=1; 116 int i; 117 p=d.getPrice(portion)*num; 118 i=(int)Math.round(p); 119 return i; 120 } 121 } 122 //订单 123 class Order { 124 Record[] records=new Record[100];//保存订单上每一道的记录 125 int getTotalPrice(int c)//计算订单的总价 126 { 127 int i,s=0; 128 for(i=1;i<=c;i++) 129 { 130 if(records[i].n==0) 131 s+=records[i].getPrice(); 132 } 133 return s; 134 } 135 Record addARecord(int orderNum,Dish d,int portion,int num)//添加一条菜品信息到订单中。 136 { 137 Record record=new Record(); 138 record.d=new Dish(); 139 record.orderNum=orderNum; 140 record.d=d; 141 record.portion=portion; 142 record.num=num; 143 return record; 144 } 145 void delARecordByOrderNum(int orderNum)//根据序号删除一条记录 146 { 147 records[orderNum].n=1; 148 } 149 }
本次作业我第一次真正地熟练了“面向对象”和灵活使用类、性质和方法。
在本次作业中,我根据题目餐馆的需求,设立了“Dish”、“Menu”、“Record”、“Order”四个类,并根据其不同的要求设立了不同的方法。以下对此做出具体分析:
Dish类:
是用来记录每一道菜。其性质为每一道菜的名字和菜价,方法则有getPrice(用来算这道菜算上份额后的总价)。
Menu类:
用来记录菜谱。其性质用来记录多道菜,方法则有searthDish(根据菜名在菜谱中寻找菜品信息)和addDish(添加一道菜品信息)。
Record类:
用来记录每一道点菜记录。其性质能记录点菜的序号,菜品信息,份额,分量,还有n来标记本记录是否被消除,方法则有:getPrice(用来计算本道订单的总价)。
Order类:
用来记录总订单。其性质记录多道点菜记录,方法则有getTotalPrice(计算总订单价钱),addARecord(添加一道点菜记录到订单中),delARecordByOrderNum(根据OrderNum来删除一条点菜记录)。
虽然因为第一次真正地完全面向对象地来写程序(上一次餐馆题目可以说是半过程半对象),所以诸多地方写起来都略显复杂,没有以最简单的方式来写(但挺意外的,代码复杂度没有超过10,我自认写的挺乱的)。而且因为一开始没有考虑到多种情况,导致后期修改过多也导致整体代码显得有些杂乱没有条理。但至少经过若干小时的修改终于有惊无险地过了全部的测试点,拿下来这40分。也算是对自己努力的一种认可。
第三次餐馆作业:

import java.time.*; import java.time.format.DateTimeFormatter; import java.util.Date; import java.util.Scanner; public class Main { public static void main(String[] args) { int a=0;//记录当前是第几桌 int d=0;//判断是否开始订单 int e=0;//判断第几道订单 int f=0; Table[] table=new Table[10]; table[0]=new Table(); table[0].menu=new Menu(); Menu menu=new Menu(); table[0].order=new Order(); Scanner in=new Scanner(System.in); while(true) { String b=in.nextLine(); if(b.equals("end")) break; String[] c=b.split(" "); if(c[0].equals("table"))//输入桌信息 { f=1; e=0; d=0; a=Integer.parseInt(c[1])-1; if(a!=0) { table[a]=new Table(); table[a].menu=new Menu(); table[a].order=new Order(); } table[a].num=a+1; table[a].date=c[2].substring(0); table[a].time=c[3].substring(0); System.out.println("table "+table[a].num+": "); continue; } if(c[0].equals("1")) d=1; if(d==0)//补充菜单 { if(table[a].menu.searthDish(c[0])==null) table[a].menu.addDish(c[0], Integer.parseInt(c[1])); else table[a].menu.searthDish(c[0]).unit_price=Integer.parseInt(c[1]); } else//开始点菜 { if(!c[1].equals("delete"))//点菜 { if(table[a].menu.searthDish(c[1])!=null) { table[a].order.addARecord(Integer.parseInt(c[0]),table[a].menu.searthDish(c[1]),Integer.parseInt(c[2]),Integer.parseInt(c[3])); System.out.println(table[a].order.records[e].OrderNum+" "+table[a].order.records[e].d.name+" "+table[a].order.records[e].getPrice()); e++; } else if(table[a].menu.searthDish(c[2])==null)//菜在菜单不存在 { if(isNumeric(c[1])) { System.out.println(c[2]+" does not exist"); table[a].order.addARecord(Integer.parseInt(c[1]),table[a].menu.searthDish(c[2]),Integer.parseInt(c[3]),Integer.parseInt(c[4])); } else { System.out.println(c[1]+" does not exist"); table[a].order.addARecord(Integer.parseInt(c[0]),table[a].menu.searthDish(c[1]),Integer.parseInt(c[2]),Integer.parseInt(c[3])); } table[a].order.records[e].e=0; e++; } else//代点菜 { table[a].order.addARecord(Integer.parseInt(c[1]),table[a].menu.searthDish(c[2]),Integer.parseInt(c[3]),Integer.parseInt(c[4])); System.out.println(c[1]+" table "+table[a].num+" pay for table "+c[0]+" "+table[a].order.records[e].getPrice()); e++; } } else//删除 { if(table[a].order.findRecordByNum(Integer.parseInt(c[0]))!=null) table[a].order.delARecordByOrderNum(Integer.parseInt(c[0])); else System.out.println("delete error;"); } } } if(f==1) { for(int i=0;i<=a;i++) { System.out.print("table "+table[i].num); if(table[i].timevalidity()==false) System.out.println(" out of opening hours"); else System.out.println(": "+table[i].getDiscountPrice()); } } } public static boolean isNumeric(String str){ for (int i = 0; i < str.length(); i++){ if (!Character.isDigit(str.charAt(i))){ return false; } } return true; } } //菜品类:对应菜谱上一道菜的信息 class Dish { String name;//菜名 int unit_price;//单价 int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) { double p=0; switch(portion) { case 1:p=unit_price*1;break; case 2:p=unit_price*1.5;break; case 3:p=unit_price*2;break; } return (int)Math.round(p); } } //菜谱类:对应菜谱,包含饭店提供的所有菜的信息。 class Menu { Dish[] dishs=new Dish[10];//保存所有菜品信息 int d=0;//记录当前菜品数量 void addDish(String name,int unit_price)//添加菜品信息 { dishs[d]=new Dish(); dishs[d].name=name.substring(0); dishs[d].unit_price=unit_price; d++; } Dish searthDish(String name)//寻找菜品信息 { for(int i=0;i<d;i++) if(name.equals(dishs[i].name)) return dishs[i]; return null; } } //点菜记录类:保存订单上的一道菜品记录 class Record { int OrderNum;//序号 Dish d;//菜品 int portion;//份额 int num;//份数 int k=1;//判断订单是否被删除 int e=1; int getPrice()//计算本条记录价格 { double s=d.getPrice(portion)*num; return (int)Math.round(s); } } //订单类:保存用户点的所有菜的信息。 class Order { Record[] records=new Record[10];//订单记录 int n=0;//记录有几道订单 void addARecord(int orderNum,Dish d,int portion,int num)//增加一条订单信息 { records[n]=new Record(); records[n].d=new Dish(); this.records[n].OrderNum=orderNum; this.records[n].d=d; this.records[n].portion=portion; this.records[n].num=num; this.n++; } Record findRecordByNum(int orderNum)//根据序号查找一条记录 { if(orderNum>0&&orderNum<=n) if(records[orderNum-1].k==1) return records[orderNum-1]; return null; } void delARecordByOrderNum(int orderNum)//根据序号删除一条记录 { records[orderNum-1].k=0; } int getTotalPrice()//计算订单总价 { int i,s=0; for(i=0;i<n;i++) { if(records[i].k==1&&records[i].e==1) s+=records[i].getPrice(); } return s; } } //桌类:保存每一桌的信息 class Table { Menu menu;//记录本桌菜单 Order order;//记录本桌订单 int num;//记录本单桌号 String date;//记录本桌日期 String time;//记录本桌时间 boolean timevalidity()//检测点单时间是否正常 { int i; int c=0; String[] a=date.split("/"); int[] b=new int[3]; for(i=0;i<3;i++) b[i]=Integer.parseInt(a[i]); if(b[1]>0&&b[1]<13)//检查日期是否正常 { if((b[1]<=7&&b[1]%2!=0)||(b[1]>=8&&b[1]%2==0))//大月 if(b[2]>0&&b[2]<32) c=1; else if(b[1]==2)//二月 { if((b[0]%4==0&&b[0]%100!=0)||b[0]%400==0)//闰年 { if(b[2]>0&&b[2]<30) c=1; } else if(b[2]>0&&b[2]<29) c=1; } else if(b[2]>0&&b[2]<31) c=1; } if(c==0) return false; String[] d=time.split("/"); for(i=0;i<3;i++) b[i]=Integer.parseInt(d[i]); c=0; if(b[0]>=0&&b[0]<24)//检查时间是否合法 if(b[1]>=0&&b[1]<60) if(b[2]>=0&&b[2]<60) c=1; if(c==0) return false; DateTimeFormatter fmt1 = DateTimeFormatter.ofPattern("y/M/d"); LocalDate date = LocalDate.parse(this.date, fmt1); int e=date.getDayOfWeek().getValue();//判断当日是星期几 if(e>0&&e<6) { if((b[0]>=17&&b[0]<20)||(b[0]>=11&&b[0]<14))//17:00-20:00||11:00-14:00 return true; else if(b[0]==20||b[0]==14)//20:00-20:30||14:00-14:30 { if(b[1]>=0&&b[1]<30) return true; else if(b[1]==30&&b[2]==0) return true; else return false; } else if(b[0]==10)//10:30-11:00 { if(b[1]>=30&&b[1]<60) return true; else return false; } } else { if(b[0]>=10&&b[0]<21)//10:00-21:00 return true; // else if(b[0]==21&&b[1]<30)//21:00-21:30 // return true; else if(b[0]==21&&b[1]==0&&b[2]==0)//21:00 return true; else if(b[0]==9)//9:30-10:00 { if(b[1]>=30&&b[1]<60) return true; else return false; } } return false; } int getDiscountPrice() { double s=0; String[] a=time.split("/"); int[] b=new int[3]; int i; for(i=0;i<3;i++) b[i]=Integer.parseInt(a[i]); DateTimeFormatter fmt1 = DateTimeFormatter.ofPattern("y/M/d"); LocalDate date = LocalDate.parse(this.date, fmt1); int e=date.getDayOfWeek().getValue();//判断当日是星期几 if(e>0&&e<6)//周一至周五 { if((b[0]>=17&&b[0]<20)||(b[0]==20&&b[1]>=0&&b[1]<30)||(b[0]==20&&b[1]==30&&b[2]==0))//17:00-20:30 s=order.getTotalPrice()*0.8; else//10:30--14:30 s=order.getTotalPrice()*0.6; } else//周六日 s=order.getTotalPrice(); return (int)Math.round(s); } }
本次作业我认为我很熟练地使用了面向对象并十分完美地写出来了代码,结果……哈哈。
总之先分析一下整体代码。在本次作业中整体沿用了上次代码中的各种类与方法,但在上次的基础上再添加了一个Table类,同时对上次类中的方法进行了一定优化与删改,下面进行具体分析。
Table类:
用于保存每一桌的信息。根据需求,需要储存每一桌的菜谱和订单,同时登记桌号,订单时间。方法则有timevalidity(用于检测点菜时间是否正常及是否在营业时间内)和getDiscountPrice(用于根据订单时间对总订单价格打折)。
同时我在Order类里增加了findRecordByNum的方法,用于根据Num来寻找相关点菜记录信息是否存在。这样一来我就增加了其相应的可寻,以判断删除时次点菜记录是否存在。
同样我对整体的主方法进行了优化。但这里没必要过多赘述(并不关键主要是我强迫症)。总之我个人是看着顺眼多了……只可惜这样的想法停止在了我提交的那一刻。这串代码并不完美,但可惜后面的测试点数据我到现在都没想通到底是哪里出了问题,只能遗憾地止步于此。
不过代码复杂度也是达到了16……虽然可读但并不完美……只可惜我的能力也使我只能止步于此了。
面向对象编程(封装性):

import java.util.Scanner; public class Main{ public static void main(String[] args) { Scanner sc = new Scanner(System.in); //调用无参构造方法,并通过setter方法进行设值 String sid1 = sc.next(); String name1 = sc.next(); int age1 = sc.nextInt(); String major1 = sc.next(); Student student1 = new Student(); student1.setSid(sid1); student1.setName(name1); student1.setAge(age1); student1.setMajor(major1); //调用有参构造方法 String sid2 = sc.next(); String name2 = sc.next(); int age2 = sc.nextInt(); String major2 = sc.next(); Student student2 = new Student(sid2, name2, age2, major2); //对学生student1和学生student2进行输出 student1.print(); student2.print(); } } /* 请在这里填写答案 */ class Student { private String sid="";//学号 private String name="";//名字 private int age;//年龄 private String major="";//专业 void setSid(String sid)//输入学号 { this.sid+=sid; } void setName(String name)//输入名字 { this.name+=name; } void setAge(int age)//输入岁数 { if(age>0) this.age=age; } void setMajor(String major)//输入专业 { this.major=major; } Student() { } Student(String sid,String name,int age,String major) { this.sid+=sid; this.name+=name; if(age>0) this.age=age; this.major+=major; } void print() { System.out.println("学号:"+sid+",姓名:"+name+",年龄:"+age+"专业:"+major); } }
这道题本身并不难,并且题目已经给了过多提示。我主要是想记录一下java的“封装性”。
它的类设置的很简单,只有Student一个类。但是要对里面的属性全部封装,所以,如何对里面的性质和方法进行赋值和取值就变成了一个问题。我们可以在申请对象的时候就对其赋值,也可以采用set、get方法。我两者均有采用。因为题目要求,所以我只写了set方法来对各种性质赋值,而没有使用get方法,而是直接使用print方法输出。
本道题并不困难,所以我也不过多赘述这道题。
踩坑心得:
第二次餐馆作业:
- 针对删除记录:我一开始并没有(忘记了)做这方面考虑,所以后期改起来也是诸多痛苦……如何删除一条点菜记录这是我思考了挺久的一点。在最后选择在点菜记录中加一个n来标记是否删除。当然,看起来解决方法挺简单的……我主要是想表达从一开始考虑就该全面,不然最后全面修改痛苦的就是自己(我)。
- 关于异常点菜记录:关于这点,我一开始的处理是对它不理、不储存。但是最后我发现它会在删除方面出问题。仔细研究后,我发现删除一个无效点菜,是不能输出“delete error;”的。所以,我最后将它处理为存为点菜,但存为异常点菜。
第三次餐馆作业:
- 关于营业时间:在我一开始的写法里,例如营业时间为17:00-20:30,我会自动默认左闭右开,也就是说,最右端的时间20:30:00这个极限时间点是不营业的。所以相关测试点错了……后面仔细看了下题目,发现题目其实有要求是闭区间,而我没有注意到这个点。所以在后面改过来,测试点便正确了。
- 关于只含菜单:我一开始真没想到这种情况,所以也没做这一手准备,所以第一次提交的时候眼前一黑,怎么会有这种情况出现……所以如果按照我原来的所写,如果只含菜单输入会非零返回,因为循环最后没有桌类数据赋值,没法输出总值……后面就加了个判断,有订单输入才能最后输出桌类订单总值。
- 关于多桌菜:我又没考虑到有只输入了菜单和桌类信息结果不点菜的情况……我说我纳闷了好久其他测试点都是答案错误,最后两个测试点怎么是非零返回呢……最后把判断挪到了桌类信息输入中。然后成功的从“非零返回”变成了“答案错误”。然后,它就再也没有变过。
- 然后就是我知道错了但是不知道错哪了……有没有大佬救救我告诉我15-23这几个测试点到底是什么……我真的改了很多种情况但是一分不加啊可恶。
面向对象编程(封装性):
- 一开始在在报错,仔细看了下,主要是因为我写了

但是原代码中有两种类型的申请新对象方式


我只写了一种申请方式所以导致了报错,于是我增加了一种:

主要困难及改进建议:
- 没有全面观察题目,而是想到一点写一点。虽然逐条分析确实带来了很多便利,但是到了最后发现有些情况需要对前面进行修改的时候就会特别痛苦。所以以后写题目还是要先总体看一遍,再逐条分析。
- 对语法的不熟悉,导致一开始解题过于困难。部分我没有列举出来的题,用到了大量我没学过的方法。为了了解那些方法我也是查了大量的资料。
- 注意细节方面。不少细节没有注意到导致在通关测试点的时候吃了很大亏。
- 还有一些凭借我个人实在是找不出的问题……下次可以多求助别人……吧……
总结:
- 教师与课程方面:真心感觉老师讲课有一点快……而且老师qq上经常选择性回复,可能是我问的问题太蠢了……但有些时候问同学也问不出来什么也挺麻烦的……
- 作业方面:真心感觉作业难度跨度有点太大了……有点接受不了了已经。而且部分操作可能见都没见过,老师也没讲过就需要开始写,这个时候查询相关资料有需要花费大量的时间精力……也是挺麻烦的。
- 实验方面:实验较为简单,可是如果和大作业一起交就有些紧凑了。
- 课上方面:真心希望老师能抽时间讲一讲大作业的题目。毕竟有些时候真的不会做,如果不讲那就放过去了也挺可惜的……

浙公网安备 33010602011771号