(1)前言(2)设计与分析(3)采坑心得(4)主要困难以及改进建议(5)总结
前言:
题目 |
知识点 |
题量(※※※※※) |
难度(※※※※※) |
点菜1 |
1.区别和学会使用了对象和类; 2.基本语法,如输入输出,基本类型和包裹类型 3.常见的处理字符串的方法 4.方法静态和不静态的使用 5.类构造方法的使用 6.使用容器arraylist ##.基本的按照现实来设计点菜思路,做到尽可能贴近现实。
|
※※ (代码量小,主要是让我们先学会写多类文件) |
※※(难度不太大。希望这个系列题目多公开测试数据,就两三个测试数据,就算这两三个测试数据过了,也不能全对。并不能理解,是不是和老师的思路有出入还是有的地方特别苛刻?) |
点菜2 |
1.属性可以进行private私有保护,并用getter和setter方法进行修改,这样就封装好了一个成员。 2.开始使用try…catch…解决字符串解析过程可能会报的错误。比如将字符串(nextLine获得的)用(split按空格拆分),将拆分的第一个pieces[0]进行数字解析(parseInt)就会出错。这就是出现异常,之后再自己按照业务的逻辑进行处理。 3.对于错误格式等输入错误,学会了多次使用if语句一次次排查,虽然代码变得十分难看,但是能对用户输入错误格式进行排查,给出提示。或者说多次正确使用elsel if语句 4.能够区分equals和==。在菜单for each找菜返回菜时。equals比较内容之间返回,==比较对象(也就是比较引用,指针,地址)返回。这一点也给我后面点菜4,埋下了坑。(有些东西就是要new出来再返回,直接返回,就要考虑返回后会不会被使用。如果会被使用(也就是修改其中的数据属性时),是不是应该在此之前要new一下,体会体会) |
※※※(代码量适中) |
※※※(初学主要第一次对字符串进行处理可能会手足无措) |
点菜3 |
1.学会代码提取和拆分,要是不进行拆分和提取,代码就会成为山,并且eclipse又不能折叠if语句和循环语句。 2.对于字符串要进行转换功能的解析,熟悉了字符串的拆分,组合,格式化输出。 3.对于准备桌子中要记录客人点菜的时间,刚开始学着使用Date类,后面发现Date和Calendar和GregorianCalendar,绝大多数方法过时,并且用法实在是啰嗦难用。后面就学习使用了LocalDateTime(也可以拆成两个子类LocalDate和LocalTIme),记录时间使用LocalDate,里面自带判断闰年等方法和Date差不多但是整合了Calendar的感觉。 4.对于时间的处理,java1.8中出现了Period、Duration,了解并且使用了其中的方法,对于营业时间处于在早上和下午之间有专门的时间处理。(后面又不用了),因为实在是没必要计算变得复杂,对字符串处理也有同样的效果。 5.计算菜的价格的时候有对数字严格要求,熟悉一下Math类中的方法。区分了round、floor、ceil这些怎么对数字取整的(是四舍五入还是向上或向下取整)。 |
※※※※(代码量,主要是体现在逻辑容易乱) |
※※※※(时间处理是向来的难点,就是很需要多多留意。刚接触java,听老师讲的少了,用的也少) |
设计与分析:
题目 | 类图(代码结构) | SourceMonito(代码质量检测) | 简单的看图分析 |
点菜1 |
整个工程不是很复杂,复杂度不高。 但是Main复杂度就挺高的,实际也还是正常的,毕竟所有的处理全交给了Main。 他这里的现实方法偏少,那么我以后写代码把Main中的过程提取成方法会不会就会有更好的可读性,或者降低复杂度呢? 只能以后试试了。 |
||
点菜2 |
工程kiviat metric图,除了最大复杂度超标,其他指标是正常的。也就是代码出现了头重脚轻的感觉,需要对特别复杂的代码进行优化。 尤其是到Main这里,方法少的可怜,复杂度全部超标,代码可能就只有自己看的懂把。 |
||
点菜3 | 这里Main图表示还是方法过少,整体复杂度高出了9倍。最大复杂度高出了3倍。这个图给我敲响警钟把,if-else或者是elif这类的分支,就是复杂度的一大凶手,需要大幅度改进。造成这么大的复杂度的原因也就是滥用分支。 |
对菜单一中具体的代码进行分析
Dish类中的计算价格
public int getPrice(int portion) {
int price = 0;
if (portion == 1) {
price = Math.round(1 * unit_price);
}
if (portion == 2) {
price = (int) Math.round(1.5 * unit_price);
}
if (portion == 3) {
price = Math.round(2 * unit_price);
}
return price;
}
Record类中的计算价格
public int getPrice() {
return d.getPrice(portion);
}
Order类中的计算价格
public int getTotalPrice() {
int sum = 0;
for (Record ck : records) {
sum += ck.getPrice();
}
return sum;
}
如上述代码一样,Order计算价钱的方法就是遍历每个Record,唤醒Record的计算价钱记录相加。而Record的唤醒Dish的计算价钱,层层调用,实际就和现实情况一样的。Dish自己根据份额计算属与自己份额的价钱返回给Record,这里Record就直接什么都不做就返回给Order(后面的Record有点菜的数量,就可以将Dish返回的价钱乘以数量,再返回给Order)。Order就算完成了任务(如果Order以后会出现折扣,对总和之后再乘以折扣。如果Order以后会有代点菜的话,也可以在计算价钱的总和进行处理)
对菜单二中比较难想的代码的分析
①如何对字符串解析。
最终我想的方法是,每次读取一行字符串(nextLine方法),我记为line。对line根据空格进行拆分(用spilt方法),记成pieces。重点来了。
如果拆分出来的pieces有2个就是准备菜单。
如果拆分出来的pieces有4个就是点菜。
如果拆分出来的pieces有2个并且pieces[1]是delete的话(pieces[1].equals("delete"))就是删除已经点了的菜。
这样我就解析了字符串,下面是代码草稿。
String line=in.nextLine();
String[] pieces=line.split(" ");
int ln=pieces.length;
if(ln==2&&!pieces[1].equals("delete")){
准备菜单;
}
else if(ln==2&&pieces[1].equals("delete"){
删除菜单;
}
if(ln==4){
点菜;
}
②如何处理点菜2中的异常情况。
其中比较有点困难的就是这个了,在准备菜单的时候,当输入多次同名菜时,菜单只保存最后一次菜的信息。
Menu.remove(Menu.searthDish(dishName));
Menu.add(dishName, unitPrice);
对菜单3的难想的点的分析
Ⅰ.对于订单时间的记录
我一开始使用的是,创建指定日期格式的simpleDateFormat对象,解析时间返回一个Date对象,放入到Order中,便于之后的处理。后面发现时间出错了。后来查阅了一下资料发现,yyyy和YYYY是不一样的,mm和MM是不一样的。yyyy才是我们现在说的公历的年份,而YYYY不是,YYYY是ISO年份,具体我就不是很清楚,总之年份用yyyy不要用YYYY,要不然有些特别的日期记录的年份就会出错。mm是minute而MM是month,这个我一开始也搞错了。
SimpleDateFormat format=new SimpleDateFormat("YYYY/MM/dd HH/mm/ss");//这个就是错误的
SimpleDateFormat format=new SimpleDateFormat("yyyy/MM/dd HH/mm/ss");//这个就是正确的
LocalDateTime dateTime=format.parse(有关于时间的字符串);
后面的话,我就弃用这个simpleDataFormat对象中的parse方法了,转向LocalDateTIme。因为我很容易搞错simpleDateFormat,除非我上网复制粘贴别人写好的。直接对时间字符串进行split("/"),被字符串被拆分成六个部分分别Integer.parseInt,得到年月日时分秒。用LocalDateTime中的of方法,放入年月日时分秒,返回一个LocalDateTime对象,放入Order中。这样就记录了时间。
Ⅱ.按订单时间算折扣
首先需要判断是否是周末,后面是不是营业时间,才能按要求计算折扣,记录在Order中。
后面使用了LocalDateTime后,在计算折扣的时候。可以取出其中部分作为LocalDate(toLocalDate方法),LocalDate又能取出是一周的哪一天(getDayOfWeek),枚举对象能取出对于的值,这里DayOfWeek的枚举是能去取出int值(使用getValue方法)。最后比较这个取出的int值,就可以判断是不是周末了。
//这里只是示意
LocalDateTime a=LocalDateTime.of(年,月,日,时,分,秒);
LocalDate b=a.toLocalDate();
int day=b.getDayOfWeek().getValue();
boolean isWeekend=false;
if(day==6||day==7){
isWeekend=true;
}
判断完是不是周末,就要判断是否是营业时间。
先确定折扣时间段的起点和终点,然后进行如果是在指定的范围就打折,不在营业范围提示错误输出。下面的示例代码会比我讲的文字更清楚。
LocalTime WeekdayDinnerTime1 = LocalTime.of(16, 59, 59);
LocalTime WeekdayDinnerTime2 = LocalTime.of(20, 31);
LocalTime WeekdayLunchTime1 = LocalTime.of(10, 29, 59);
LocalTime WeekdayLunchTime2 = LocalTime.of(14, 31);
LocalTime weekendOpenningTime1 = LocalTime.of(9, 29, 59);
LocalTime weekendOpenningTime2 = LocalTime.of(21, 31, 00);
if (!isWeekend) {
if (isIn(订单时间, weekdayDinnerTime1, weekdayDinnerTime2))
discount = 0.8;
else if (isIn(订单时间, weekdayLunchTime1, weekdayLunchTime2))
discount = 0.6;
else
System.out.println("table " + tableNum + " out of opening hours");
} else {
if (isIn(订单时间, weekendOpenningTime1, weekendOpenningTime2)){
discount = 1.0;//由于我的代码最后的总价一定会乘以discount,这一行不能省略。
}else{
System.out.println("table " + tableNum + " out of opening hours");
}
}
Ⅲ.代点菜部分
首先查找要给哪个桌子代点菜,找到这个table。然后再解析要代点的菜,进行的相对应的处理。
我先写了一个找桌子的方法,然后当前的桌子currentTable是实时按照输入更新的,currentTable就给找到的桌子增加订单,addARecord给找到的table,自己currentTable则只是记录一下要付的钱(extraMoney),而找到的table的extraMoney就是相反数。最后总价计算,还是符合题意,就草草就这样完成了个代点菜功能。我觉得代点菜,我这里可能没有符合现实。所以有点困惑,后面看到某个老师写的代码,发现现实生活中的确,订单就要分自己吃的菜,和自己高兴给别人点的菜,订单是都应该记录在自己currentTable。而不是像我一样,记录在找到的table上,不符合现实逻辑。
踩坑心得:
1.simpleDateFormat解析的坑,yyyy与YYYY;
2.使用for-each循环遍历dishes(菜单上的菜),直接返回菜单上的菜这个对象,后面对这个返回值进行创建新的订单,这就难免会对这个返回值进行修改。这就直接对菜单进行修改了,可是菜单是不会变的,一开始由店家的输入就确定了。后面如果要用返回值的修改的话,就进行new一下再返回,这样就不用担心菜单会在创建订单的过程中改变,也就避免牵一发而动全身了。
3.周末的discount没有赋值,导致最后在周末的桌子清算价格的时候全是0。(特别小的坑,很快就解决了)。
4.订单价格和预期价格总是差1元。找了很久发现是四舍五入的顺序出错了。可是我后面按照题目的顺序只有80%的订单是可以得到正确的价格的,其他的20%都会差1元,真的很心累吧。现在之间还未解决。
其他的坑不太显著,就是很快就能解决,以上写的就是卡了很久的坑。
主要困难已经改进建议:
1.对订单价格的计算,如设计与分析中的菜单一中代码分析。
2.对字符串的解析,如设计与分析中的菜单二而的难点分析。
3.日期的处理,如设计与分析中菜单三的难想到的点的分析。
4.后面想了想字符串的解析,可以匹配正则表达式的方法,也在菜单4后面的代码体现了。
5.后面的delete duplication可以用set容器,有查重的功能,如果已经在集合存在了,那么就输出删除重复语句。
具体的主要困难,在分析代码的时候就已经体现,分析代码就是面对主要困难时的心路体现。具体的改进其实也有体现。
总结:
学到了什么,哪些地方需要进一步学习及研究,对教师、课程、作业、实验、课上及课下组织方式等方面的改进建议及意见。
菜单这个程序对新手来说难度还是很大的,尤其时像我这种刚入门的,在这里只能说,难有难的好吧。难可以把许多知识点一起复习带过,但是不能很容易让初学者满分,甚至可以初学者没有一次满分过,有点打击自信心。如果点菜系列的公开测试点不是简略的5、6个。或者一些苛刻的点给出模板样例,不要只用文字寥寥几笔带过。有的时候你不知道提示难点一下,就能过去绝大多数测试点,能给很多自信。
总之还是收获,难有难的好,可以提升和进阶。简单又简单的妙处,也能让自己熟悉使用一些基本语法。
需要进一步学习的就是对字符串的处理方法。和如果自己程序正常出现题目中所给的错误输入的话,怎么样才能不要一直if-esle这样一坨一坨的堆叠代码,难维护的代码,又复杂度的增高,势必会对以后程序可持续化加大难度。这不就体现在菜单4吗,菜单4中17个异常情况,用实验3的代码来说,全在那里加if-else,像座山的代码,实现了其中的异常处理功能。这样的代码是真正想要的吗?自己做了菜单才能理解,有些封装是必要的,如果没有封装,则需要大刀阔斧的修改。也是做了菜单才能理解,有些看起来方便的if-else,可能是危险累计的开始,对于异常的处理,越独立越好,如果能减少分支也是给维护人员的一口喘息把。
最大的建议和意见,希望不要只是寥寥在题目集上面写一段提示文字,而是给多测试点,有的时候都过去了测试点,就是不能全对,现在的pta又关闭了测试点中的标准输出,自己去想测试样对目前的自己还是很难的。或者多给一点代码提示,尤其是价格计算的时候,你以为你按照题目做清楚功能了,结果就差个1,无论你怎么样修改(int)和(Math.round)的位置,增加还是删除(Math.round),能过去大部分的点,别的小点,最终又是答案错误,又看不到标准的输出应该是什么。
这个题目收获不止如此,只能说学java做到就是赚到把。
标签:菜单,int,代码,字符串,点菜,三次,LocalTime From: https://www.cnblogs.com/liujiantao/p/17410161.html