OO题目集4-6总结
Posted 肖_xyt
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OO题目集4-6总结相关的知识,希望对你有一定的参考价值。
一、前言
题目集四
从本次题目集开始,正式开始了菜单类设计,并熟悉了字符串各常用语法的运用,及运用封装性进行面向对象编程。七道题目,菜单3难度稍高,其他中等。
题目集五
本次题目集集中训练了正则表达式,以及日期问题的面向对象聚合设计。总体难度不大,题量也只有六道,不多,主要是熟悉正则的用法以及如何实现聚合。
题目集六
在这次题目集中仅一道菜单类题目,是题目集四菜单类的再次迭代,虽然题目量少,但相较于其他题目集花费时间却更多,题目代码量更多,类与类之间的设计也更加复杂难以下手。
二、设计与分析
---题目集4-1,题目集6-1
1、题目
(1) 题目集4-1
(2) 题目集6-1
2、分析:
题目集4-1是菜单类题目的第三次迭代,刚开始的时候,由于没有写过菜单1和菜单2,看到这么长的题目还是挺手足无措的,不知道从哪里开始下手,总是会有一点逃避心理的,再加上在题目集3中并不是只有这一道题目,一开始就先打算完成其他题目再来慢慢写,没想到在其他题目上也被卡了很久,导致最后在设计分析这道题的时候,时间也不多了,类间关系混乱,很多地方都没有考虑到,最后也没有写完。
在编写本次blog时,是已经经历过题目集6-1的菜单4了,现在一对比菜单4,菜单3的条件等等都相对非常简化版本的了,现在反思当时的小小逃避心理真的是非常后悔的(欠下的债总是要还的),而由于当时的我对于菜单3并没有好好的分析,使我在菜单4的更复杂的题目中花费了大量时间来抽离主干、分析设计。
由上面的图片可以看到,菜单类设计主要是分为两个板块,一个是输入菜谱,一个是输入订单,而菜单4则比菜单3增加了十几条异常情况判断和一种功能增加。在菜单类的设计中,我也在和同学讨论如何改进菜单各个情况的处理的过程中收获了许多。
(1) 比如说菜单4的输入格式等方面判断,一开始我使用的是字符串输入,split分割成字符串数组再来一一判断,但是这样就会漏掉比如多个空格等错误情况,后来在交流中,发现可以用正则表达来判断会更加全面;
原来的:
改进后:
(2) 还有格式错误这些小细节,在写代码中,输出基本是自己按照题目去写格式,由于各个地方的判断输出都比较多,输入时不可能所有的内容直接复制格式在一起输入,那么一些小细节的地方就会完全发现不了,比如:
在这里的冒号后面其实是有一个空格的,但是如果是自己对照着一个个写格式,这里是绝对不会发现不了还有一个空格,这个点也是我在同学的提醒下才发现的。
(3)在菜单类4中,由于异常判断较多,时常会出现各种问题。比如在这里判断后,是直接输出吗,还是要延迟输出;是先判断这个,还是先判断哪个等等,由于我的各个方法是在对应的类中实现,并不能说是非常直观的在代码中看到功能以及效果,导致了许多混乱,后来在与同学的复盘中也提到了,说我的代码看起来就像在不停的打补丁一样,这里缺了一点就补一下,那里缺了一点再补一下,程序结构非常混乱,PTA的提交分数也是飘忽不定,这是需要改正的。
关于菜单的类与类的设计,现在最后的版本相比较于最初的想法基本上可以说是毫不相干了,在逐渐完成代码的时候,一步步加上各种功能,发现现在的类不能满足需求,又重新设计,添加上新的类,不断修改修改,在这次题目集中,确实是感觉到自己成长了许多。
对于本次题目集中的菜单类问题,后期发现确实是在算法上没有什么难点,在我看来它更多地是在考验逻辑思维,细心程度,分析解决问题能力以及和同学伙伴间的交流能力,而不是要自己闭门造车。
最后的类图如下:
设计了Dish菜品类,Menu菜谱类,TableNumberIdentification桌号类,Record单条点菜记录类,Order单条订单类,BlanketOrder总订单类。Menu -> Dish,BlanketOrder -> Order -> Record和 TableNumberIdentification。
数据分析如下:
---题目集5-5,题目集5-6
这两道题是在上次总结中也有写过的日期问题的两种不同的聚合关系的写法,虽然大体上算法大差不差,但是在类的结构,内容上随着类间关系的变化也是导致代码产生了许多变化。
类图如下:
(1) 题目集5-5
(2) 题目集5-6
在5-5中,是按照中介 -> 年 -> 月 -> 日的聚合方式,是一级比一级要大的,而在5-6中,则是中介 -> 年,月,日的聚合方式,在中介的下面,年月日是同样的地位,这是两种聚合的主要不同。那么随着变化,类内的方法和属性肯定也是不同的。
这两道题难度都不大,我认为主要是想让我们熟悉并运用聚合关系。
最后代码如下:
(1) 题目集5-5
import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Main public static void main(String[] args) Scanner in = new Scanner(System.in); int choice = in.nextInt(); if(choice == 1)//求下n天 int y = in.nextInt(); int m = in.nextInt(); int d = in.nextInt(); DateUtil dateUtil = new DateUtil(y,m,d); int n = in.nextInt(); if (!dateUtil.checkInputValidity() || n < 0) System.out.println("Wrong Format"); System.exit(0); dateUtil.getNextDays(n); System.out.println(dateUtil.showDate()); else if(choice == 2)//求前n天 int y = in.nextInt(); int m = in.nextInt(); int d = in.nextInt(); DateUtil dateUtil = new DateUtil(y,m,d); int n = in.nextInt(); if (!dateUtil.checkInputValidity() || n < 0) System.out.println("Wrong Format"); System.exit(0); dateUtil.getPreviousDays(n); System.out.println(dateUtil.showDate()); else if(choice == 3)//求相差天数 int y = in.nextInt(); int m = in.nextInt(); int d = in.nextInt(); DateUtil dateUtil1 = new DateUtil(y,m,d); int yy = in.nextInt(); int mm = in.nextInt(); int dd = in.nextInt(); DateUtil dateUtil2 = new DateUtil(yy,mm,dd); if (!dateUtil1.checkInputValidity() || !dateUtil2.checkInputValidity()) System.out.println("Wrong Format"); System.exit(0); System.out.println(dateUtil1.getDaysofDates(dateUtil2)); else System.out.println("Wrong Format"); System.exit(0); class Year//年 private int value; public Year() public Year(int value) this.value = value; public void setValue(int value) this.value = value; public int getValue() return value; public boolean isLeapYear()//判断闰年 if(value % 400 == 0 || (value % 100 != 0 && value % 4 == 0)) return true; return false; public boolean validate()//判断输入是否合法 if(value >= 1900 && value <= 2050) return true; return false; public void yearIncrement() value ++; public void yearReduction() value --; class Month private int value; private Year year; public Month() public Month(int yearValue,int monthValue) this.value = monthValue; year = new Year(yearValue); public void setValue(int value) this.value = value; public int getValue() return value; public void setYear(Year year) this.year = year; public Year getYear() return year; public void resetMin() value = 1; public void resetMax() value = 12; public boolean validate()//判断输入是否合法 if(value >= 1 && value <= 12) return true; return false; public void monthIncrement() value ++; public void monthReduction() value --; class Day private int value; private Month month; private int[] mon_maxnum = 31,28,31,30,31,30,31,31,30,31,30,31; public Day() public Day(int yearValue,int monthValue,int dayValue) this.value = dayValue; month = new Month(yearValue,monthValue); public void setValue(int value) this.value = value; public int getValue() return value; public void setMonth(Month month) this.month = month; public Month getMonth() return month; public void resetMin() value = 1; public void resetMax() value = mon_maxnum[month.getValue()]; public boolean validate()//判断输入是否合法 if(month.getYear().isLeapYear() && month.getValue() == 2) if(value >= 1 && value <= 29) return true; if(value >= 1 && value <= mon_maxnum[month.getValue() - 1]) return true; return false; public void dayIncrement() value ++; public void dayReduction() value --; class DateUtil private Day day; public DateUtil() public DateUtil(int y,int m,int d) day = new Day(y,m,d); public Day getDay() return day; public void setDay(Day d) this.day = day; public boolean checkInputValidity() if(day.getMonth().getYear().validate()) if(day.getMonth().validate()) if(day.validate()) return true; return false; public boolean compareDates(DateUtil date)//比较大小 if(day.getMonth().getYear().getValue() < date.getDay().getMonth().getYear().getValue()) return true;//年小 if(day.getMonth().getYear().getValue() == date.getDay().getMonth().getYear().getValue()) if(day.getMonth().getValue() < date.getDay().getMonth().getValue()) return true;//年等,月小 if(day.getMonth().getYear().getValue() == date.getDay().getMonth().getYear().getValue()) if(day.getMonth().getValue() == date.getDay().getMonth().getValue()) if(day.getValue() <= date.getDay().getValue()) return true;//年等月等,日小 return false; public boolean equalTwoDates(DateUtil date)//比较是否相等 if(day.getMonth().getYear().getValue() == date.getDay().getMonth().getYear().getValue()) if(day.getMonth().getValue() == date.getDay().getMonth().getValue()) if(day.getValue() == date.getDay().getValue()) return true;//年等月等日等 return false; public String showDate()//格式化日期 return day.getMonth().getYear().getValue() + "-" + day.getMonth().getValue() + "-" + day.getValue(); public DateUtil getNextDays(int n)//求下n天 Day temp; long num = 0; int YearNum = 365; if(day.getMonth().getYear().isLeapYear()) YearNum = 366; for(int i = 0;i < day.getMonth().getValue() - 1;i ++) temp = new Day(0,0,0);//设立一个新的Day类,用来累加 temp.getMonth().setValue(i);//把当前要加上的月份赋给他 temp.resetMax();//把本月的最大天数赋值 if(day.getMonth().getYear().isLeapYear() && i == 1) num = num + temp.getValue() + 1; else num += temp.getValue(); num += day.getValue(); num += n; //跨年了,有可能跨了不止一年 while(num > YearNum) day.getMonth().getYear().yearIncrement();//年份加一 num -= YearNum; if(day.getMonth().getYear().isLeapYear()) YearNum = 366; else YearNum = 365; day.setValue(0); day.getMonth().setValue(1); int i = 0; temp = new Day(0,0,31); while(num > temp.getValue()) if(day.getMonth().getYear().isLeapYear() && i == 1)//闰年的二月 num = num - temp.getValue() - 1; else num-= temp.getValue(); temp.getMonth().monthIncrement(); day.getMonth().monthIncrement(); i ++; temp.getMonth().setValue(i); temp.resetMax(); day.setValue((int)num); return this; public DateUtil getPreviousDays(int n)//求前n天 Day temp; long num = 0; int YearNum = 365; if(day.getMonth().getYear().isLeapYear()) YearNum = 366; for(int i = 0;i < day.getMonth().getValue() - 1;i ++) temp = new Day(0,0,0);//设立一个新的Day类,用来累加 temp.getMonth().setValue(i);//把当前要加上的月份赋给他 temp.resetMax();//把本月的最大天数赋值 if(day.getMonth().getYear().isLeapYear() && i == 1) num = num + temp.getValue() + 1; else num += temp.getValue(); num += day.getValue(); num -= n; //跨年了,有可能跨了不止一年 while(num <= 0) day.getMonth().getYear().yearReduction();//年份减一 if(day.getMonth().getYear().isLeapYear()) YearNum = 366; else YearNum = 365; num += YearNum; day.setValue(0); day.getMonth().setValue(1); int i = 0; temp = new Day(0,0,31); while(num > temp.getValue()) num -= temp.getValue(); temp.getMonth().monthIncrement(); day.getMonth().monthIncrement(); i ++; temp.getMonth().setValue(i); temp.resetMax(); if(day.getMonth().getYear().isLeapYear() && i == 1)//闰年的二月 temp.setValue(29); day.setValue((int)num); return this; public int getDaysofDates(DateUtil date)//求相差天数 int yearMin,yearMax; int numMin = 0,numMax = 0; Day temp,dayMax,dayMin; int YearNum = 365; if(day.getMonth().getYear().isLeapYear()) YearNum = 366; if(this.compareDates(date)) //this <= date yearMax = date.getDay().getMonth().getYear().getValue(); yearMin = this.getDay().getMonth().getYear().getValue(); dayMax = new Day(date.getDay().getMonth().getYear().getValue(),date.getDay().getMonth().getValue(),date.getDay().getValue()); dayMin = new Day(day.getMonth().getYear().getValue(),day.getMonth().getValue(),day.getValue()); else yearMax = this.getDay().getMonth().getYear().getValue(); yearMin = date.getDay().getMonth().getYear().getValue(); dayMax = new Day(day.getMonth().getYear().getValue(),day.getMonth().getValue(),day.getValue()); dayMin = new Day(date.getDay().getMonth().getYear().getValue(),date.getDay().getMonth().getValue(),date.getDay().getValue()); //以小的年份为基准,用大的来-- //计算小的年份在本年的天数 for(int i = 0;i < dayMin.getMonth().getValue() - 1;i ++) temp = new Day(0,0,0);//设立一个新的Day类,用来累加 temp.getMonth().setValue(i);//把当前要加上的月份赋给他 temp.resetMax();//把本月的最大天数赋值 if(dayMin.getMonth().getYear().isLeapYear() && i == 1) numMin = numMin + temp.getValue() + 1; else numMin += temp.getValue(); numMin += dayMin.getValue(); //计算大的年份在本年的天数 for(int i = 0;i < dayMax.getMonth().getValue() - 1;i ++) temp = new Day(0,0,0);//设立一个新的Day类,用来累加 temp.getMonth().setValue(i);//把当前要加上的月份赋给他 temp.resetMax();//把本月的最大天数赋值 if(dayMax.getMonth().getYear().isLeapYear() && i == 1) numMax = numMax + temp.getValue() + 1; else numMax += temp.getValue(); numMax += dayMax.getValue(); //再加上差的每一年的天数 while(yearMin != yearMax) yearMax --; if((yearMax % 400 == 0)||(yearMax % 100 != 0 && yearMax % 4 == 0)) numMax += 366; else numMax += 365; numMax -= numMin; return numMax;
(2) 5-6
import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Main public static void main(String[] args) Scanner in = new Scanner(System.in); int choice = in.nextInt(); if(choice == 1)//求下n天 int y = in.nextInt(); int m = in.nextInt(); int d = in.nextInt(); DateUtil dateUtil = new DateUtil(y,m,d); int n = in.nextInt(); if (!dateUtil.checkInputValidity() || n < 0) System.out.println("Wrong Format"); System.exit(0); System.out.print(dateUtil.showDate() + " next " + n + " days is:"); dateUtil.getNextDays(n); System.out.println(dateUtil.showDate()); else if(choice == 2)//求前n天 int y = in.nextInt(); int m = in.nextInt(); int d = in.nextInt(); DateUtil dateUtil = new DateUtil(y,m,d); int n = in.nextInt(); if (!dateUtil.checkInputValidity() || n < 0) System.out.println("Wrong Format"); System.exit(0); System.out.print(dateUtil.showDate() + " previous " + n + " days is:"); dateUtil.getPreviousDays(n); System.out.println(dateUtil.showDate()); else if(choice == 3)//求相差天数 int y = in.nextInt(); int m = in.nextInt(); int d = in.nextInt(); DateUtil dateUtil1 = new DateUtil(y,m,d); int yy = in.nextInt(); int mm = in.nextInt(); int dd = in.nextInt(); DateUtil dateUtil2 = new DateUtil(yy,mm,dd); if (!dateUtil1.checkInputValidity() || !dateUtil2.checkInputValidity()) System.out.println("Wrong Format"); System.exit(0); System.out.print("The days between " + dateUtil1.showDate() + " and " + dateUtil2.showDate() + " are:"); System.out.println(dateUtil1.getDaysofDates(dateUtil2)); else System.out.println("Wrong Format"); System.exit(0); class Year//年 private int value; public Year() public Year(int value) this.value = value; public void setValue(int value) this.value = value; public int getValue() return value; public boolean isLeapYear()//判断闰年 if(value % 400 == 0 || (value % 100 != 0 && value % 4 == 0)) return true; return false; public boolean validate()//判断输入是否合法 if(value >= 1820 && value <= 2020) return true; return false; public void yearIncrement() value ++; public void yearReduction() value --; class Month private int value; public Month() public Month(int value) this.value = value; public void setValue(int value) this.value = value; public int getValue() return value; public void resetMin() value = 1; public void resetMax() value = 12; public boolean validate()//判断输入是否合法 if(value >= 1 && value <= 12) return true; return false; public void monthIncrement() value ++; public void monthReduction() value --; class Day private int value; public Day() public Day(int value) this.value = value; public void setValue(int value) this.value = value; public int getValue() return value; public void dayIncrement() value ++; public void dayReduction() value --; class DateUtil private Day day; private Month month; private Year year; private int[] mon_maxnum = 31,28,31,30,31,30,31,31,30,31,30,31; public DateUtil() public DateUtil(int y,int m,int d) day = new Day(d); month = new Month(m); year = new Year(y); public Day getDay() return day; public void setDay(Day d) this.day = d; public Month getMonth() return month; public void setMonth(Month month) this.month = month; public Year getYear() return year; public void setYear(Year year) this.year = year; public void setDayMax() //if(month.getValue() >= 1) day.setValue(mon_maxnum[month.getValue()]); public void setDayMin() day.setValue(1); public boolean checkInputValidity() int d; if(year.validate()) if(month.validate()) d = mon_maxnum[month.getValue() - 1]; if(day.getValue() >= 1 && day.getValue() <= d) return true; return false; public boolean compareDates(DateUtil date)//比较大小 if(year.getValue() < date.getYear().getValue()) return true;//年小 if(year.getValue() == date.getYear().getValue()) if(month.getValue() < date.getMonth().getValue()) return true;//年等,月小 if(year.getValue() == date.getYear().getValue()) if(month.getValue() == date.getMonth().getValue()) if(day.getValue() <= date.getDay().getValue()) return true;//年等月等,日小 return false; public boolean equalTwoDates(DateUtil date)//比较是否相等 if(year.getValue() == date.getYear().getValue()) if(month.getValue() == date.getMonth().getValue()) if(day.getValue() == date.getDay().getValue()) return true;//年等月等日等 return false; public String showDate()//格式化日期 return year.getValue() + "-" + month.getValue() + "-" + day.getValue(); public DateUtil getNextDays(int n)//求下n天 DateUtil temp = new DateUtil(0,0,0);//设立一个新的Day类,用来累加; long num = 0; int YearNum = 365; if(year.isLeapYear()) YearNum = 366; for(int i = 0;i < month.getValue() - 1;i ++) temp.getMonth().setValue(i);//把当前要加上的月份赋给他 temp.setDayMax();//把本月的最大天数赋值 if(year.isLeapYear() && i == 1) num = num + temp.getDay().getValue() + 1; else num += temp.getDay().getValue(); num += day.getValue(); num += n; //跨年了,有可能跨了不止一年 while(num > YearNum) year.yearIncrement();//年份加一 num -= YearNum; if(year.isLeapYear()) YearNum = 366; else YearNum = 365; day.setValue(0); month.setValue(1); int i = 0; temp = new DateUtil(0,0,31); while(num > temp.getDay().getValue()) if(year.isLeapYear() && i == 1)//闰年的二月 num = num - temp.getDay().getValue() - 1; else num -= temp.getDay().getValue(); temp.getMonth().monthIncrement(); month.monthIncrement(); i ++; temp.getMonth().setValue(i); temp.setDayMax(); day.setValue((int)num); return this; public DateUtil getPreviousDays(int n)//求前n天 DateUtil temp = new DateUtil(0,0,0);//设立一个新的Day类,用来累加; long num = 0; int YearNum = 365; if(year.isLeapYear()) YearNum = 366; for(int i = 0;i < month.getValue() - 1;i ++) temp.getMonth().setValue(i);//把当前要加上的月份赋给他 temp.setDayMax();//把本月的最大天数赋值 if(year.isLeapYear() && i == 1) num = num + temp.getDay().getValue() + 1; else num += temp.getDay().getValue(); num += day.getValue(); num -= n; //跨年了,有可能跨了不止一年 while(num <= 0) year.yearReduction();//年份减一 if(year.isLeapYear()) YearNum = 366; else YearNum = 365; num += YearNum; day.setValue(0); month.setValue(1); int i = 0; temp = new DateUtil(0,0,31); while(num > temp.getDay().getValue()) num -= temp.getDay().getValue(); temp.getMonth().monthIncrement(); month.monthIncrement(); i ++; temp.getMonth().setValue(i); temp.setDayMax(); if(year.isLeapYear() && i == 1)//闰年的二月 temp.getDay().setValue(29); day.setValue((int)num); return this; public int getDaysofDates(DateUtil date)//求相差天数 int yearMin,yearMax; long numMin = 0,numMax = 0; DateUtil temp,dayMax,dayMin; int YearNum = 365; if(year.isLeapYear()) YearNum = 366; if(this.compareDates(date)) //this <= date yearMax = date.getYear().getValue(); yearMin = this.getYear().getValue(); dayMax = new DateUtil(date.getYear().getValue(),date.getMonth().getValue(),date.getDay().getValue()); dayMin = new DateUtil(year.getValue(),month.getValue(),day.getValue()); else yearMax = this.getYear().getValue(); yearMin = date.getYear().getValue(); dayMax = new DateUtil(year.getValue(),month.getValue(),day.getValue()); dayMin = new DateUtil(date.getYear().getValue(), date.getMonth().getValue(), date.getDay().getValue()); //以小的年份为基准,用大的来-- //计算小的年份在本年的天数 for(int i = 0;i < dayMin.getMonth().getValue() - 1;i ++) temp = new DateUtil(0,0,0);//设立一个新的Day类,用来累加 temp.getMonth().setValue(i);//把当前要加上的月份赋给他 temp.setDayMax();//把本月的最大天数赋值 if(year.isLeapYear() && i == 1) numMin = numMin + temp.getDay().getValue() + 1; else numMin += temp.getDay().getValue(); numMin += dayMin.getDay().getValue(); //计算大的年份在本年的天数 for(int i = 0;i < dayMax.getMonth().getValue() - 1;i ++) temp = new DateUtil(0,0,0);//设立一个新的Day类,用来累加 temp.getMonth().setValue(i);//把当前要加上的月份赋给他 temp.setDayMax();//把本月的最大天数赋值 if(year.isLeapYear() && i == 1) numMax = numMax + temp.getDay().getValue() + 1; else numMax += temp.getDay().getValue(); numMax += dayMax.getDay().getValue(); //再加上差的每一年的天数 while(yearMin != yearMax) yearMax --; if((yearMax % 400 == 0)||(yearMax % 100 != 0 && yearMax % 4 == 0)) numMax += 366; else numMax += 365; numMax -= numMin; return (int)numMax;
三、踩坑心得
---题目集4-2
这道题几个错误都是运行超时导致的,在修改中发现将x的定义挪出循环外后有一个点的运行超时就通过了,仔细分析发现应该是一直定义不断增加占据空间的同时拖慢了运行速度,还是一些基础不牢固导致的,这种错误是不应该出现的,要多多注意。
---题目集4-3
本题在题目集三中出现过类似题目,在一开始写的时候我原本也是按照之前的思路进行设计,但在提交后发现总是会运行超时。
尝试改变算法(增加改变判断条件),改变元素的储存方式(ArrayList)之类的,都一直还是超时,后来在和同学的的讨论中不断尝试,最后用到了LinkedHashSet才终于通过。
---题目集4-4
在本题中主要踩的坑是由于对于 split() 这个语法点的学习不够全面,知识没有掌握到位,split的()内当多个条件出现时,是有顺序的判断,从前往后,判断符合了第一个,就会跳过已经判读的字符,开始下一轮判断。
由于知识学习的不全面,导致只能在不断地测试试错中发现正确的用法,我认为这是非常需要改进的。而在试错的同时,也没有仔细分析错误的可能和与同学讨论可能原因,只是盲目的测试,也浪费了许多不必要的时间。
最后代码如下:
import java.util.Arrays; import java.util.ArrayList; import java.util.Scanner; public class Main public static void main(String[] args) String ch; Scanner in = new Scanner(System.in); String s = in.nextLine(); String[] str = s.split("\\\\. |\\\\, |\\\\.|\\\\ "); int strLon = str.length; int i,j; Arrays.sort(str,String.CASE_INSENSITIVE_ORDER);//所有的元素按字母序排序 for(i = strLon - 1;i >= 1;i --)//按字数排序 for(j = i - 1;j >= 0;j --) if(str[i].length() <= str[j].length()) ch = str[i]; str[i] = str[j]; str[j] = ch; ArrayList<String> newStr = new ArrayList<>(); for(i = strLon - 2;i >= 0;i --) if(!str[i + 1].equals(str[i])) newStr.add(str[i]); int newStrLon = newStr.size(); System.out.println(str[strLon - 1]); for(i = 0;i < newStrLon;i ++) System.out.println(newStr.get(i));
四、改进建议
(1)菜单类题目:在上面分析中我也曾提到过,写代码和打补丁一样,哪里缺了补哪里,当时是由于连题目都完成不了,就也没想那么多,把要修正的直接写上去了,发现时也来不及又修改又继续往下写了。这给了我很大的教训,这种代码编写想法是需要在以后改正的。
(2) 代码的各种小问题在这几次的题目集中我也是经常犯。比如在循环里每次重定义一个数,使题目大大增加运行时间;循环判断true/false写反了;题目阅读不仔细,出错了才反应过来等等。
五、总结
1、综合性总结
(1) 对于知识学习的不全面:如上面所说的 split 的用法由于了解不全面,导致一直出错。还有循环里的重定义,这也是对知识的掌握不全面导致的。
(2) 细节问题总是出错:像格式错误,读题不仔细这种,确实是不应该犯的错误。
(3) 对于题目条件间的逻辑:这个在菜单类题目中体现得非常明显,没有总体的意识,看一步走一步的,非常容易使自己逻辑混乱,一步错步步错的。以后要从类图开始着手,整理好类间逻辑再开始。
2、对于教师、课程、作业、实验及课上课下组织方式的改进建议以及意见
如果可以的话,希望以后可以开放题目集的补集。就是和原题目集一样的题目,但是成绩不参与平时成绩的计算。我觉得开放补集,可以在学习到了更多知识,有了更好的对于题目的想法和想要改进之前的算法的时候对于各种想法正确与否进行验证,只是与以往程序对照可能会出现疏漏。
OO第三次博客作业总结
20201124-熊彩虹
一、分析与总结
1、第七次作业
(1)作业总体总结:
第七次作业只有两道题目,题目量适中。其中两道题都是对图形面积的处理,但第二题稍微要比第一题稍加复杂些许。在刚接触题目一的时候,觉得题目稍微有一些棘手,但是在解决第一道题之后,就大致理解题目的解决思路。在知识点方面,两道题都是考验了对类的设计,以及继承、多态的运用,考察程序是否符合的“单一职责原则”,“开-闭”原则。其次在第二道题中考察了对泛型的使用,和Comparable、Comparator 接口的应用。7-2相较于7-1还增加了对ArrayList 工具类的使用。
(2)题目分析:
1)7-1分析:
圈复杂度:
类图:
分析:在类的设计方面,对圆形(Circle)、矩形(Rectangle)、三角形(Triangle)及梯形(Trapezoid)均设计了一个类,使得程序符合“单一职责原则”,除此之外设计了一个Shape类,而各个图形均继承自Shape类,并在Shape类中写入抽象的处理面积的方法,在各个图形类中再根据各个图形不同的求面积方法复写处理面积的方法,实现了代码的多态。在该题中,因为有要求要将每个所得数据经行大小排序。第一反应是使用冒泡排序法或者其他方法解决,但经过老师的提示之后,选择使用了ArrayList 工具类中的cardSort()方法,该方法可以直接将ArrayList中的数据按从大到小的顺序排序,使得代码更加简洁。
2)7-2分析
圈复杂度:
类图:
分析:由于第二题是在第一题的程序上进行深入研究,因此在第一题累计下来的不少经验在第二题中也适用。比如对程序类设计的思路以及ArrayList工具的使用在。除去两道题的相似点之外,第二题涉及了接口以及泛化的知识点,还有Comparator和Comparable。其中泛化了解了是一种继承关系,表示一般与特殊的关系,它指定了子类如何特化父类的所有特征和行为。Comparable是在集合内部定义的方法实现的排序,Comparator是在集合外部实现的排序。简单一点即是Comparable是将类内部的和外部传入的比较排序,而Comparator是将两个需要比较的值均传入类中,再将二者进行比较,得出结论。
(3)踩坑心得
1、在刚拿到题目时,看到有考察排序算法的时候,第一个反应是使用冒泡排序法等算法,但是在得知有ArrayList工具之后,立马决定改用ArrayList工具,这在很大程度上简略了程序,缩减了代码长度等。
2、在对比Comparable和Comparator方法时,二者均进行了尝试。首先是Comparable,由于这个方法是将内部的数据与外部传入的数据进行比较得出结论,又因为在类设计时,将Card类继承自Comparable,于是在在Card类中具体实现比较的方法,这样在实际调用比较方法时则可以直接将对象的数据与其他数据进行比较。第二个是Comparator方法,这是将两个需要被比较的对象同时传入方法中,若是使用这个方法,Card类就可以不继承自Comparator方法也可以直接调用(使用双重循环就能将动态数组中的数据传入),即在Comparator中就将比较方法写全。但是这样的话,程序的灵活性就稍微没有使用Comparable好,因为若是在日后需要增加一种新的比较方法,就比较不方便,因此使用接口来完成程序是非常有必要的,但同时也要牢记“开闭原则”。
(4)改进建议
通过这一次的作业,对ArrayList工具类有了一定的熟练度,对接口方面和Comparable,Comparator也有了更深入的理解,但是这次的作业还是反映出了一些问题。首先就是对类间关系中的泛化不够熟练,需要尽快查阅关于“泛化”的资料,掌握它。
2、第八次作业、第九次作业
(1)作业总体总结:
这两次的题目都只有一道题,且题目内容是不断更进的,于是将这两次的作业放到了这块儿总结。首先两次作业的题目量都不多,但是作业都有一定难度。题目是要求对银行用户在 ATM 机上进行相关操作的模拟系统设计,考察了我们对类的设计,以及实体类和业务类的理解。程序存取款问题实际上并不是特别难,但是题目考察了许多知识点。首先是对AraayList的查找。用户在ATM机上输入卡号,我们需要从用户输入的卡号获取用户的账户所隶属的银行等信息,于是需要使用查询的方法。第一次作业使用的是从上往下查询的方法,第二次作业使用了从下往上查询的方法,因此也学习到了双向绑定的知识点。从下往上查询的方法相较于从上往下查询的方法效率也会更高。在第九次的作业中还增加了借记卡和信用卡的区分,跨行收取手续费以及超支收取手续费的问题,在第八次作业的基础上难度更上一层楼。
(2)题目分析:
1)第八次作业
圈复杂度:
类图:
分析:在这一次作业中依旧是考察了类以及类间关系的设计,这一次作业不像以往的作业一样给了类图或提示,这一次只给定了实体类,除去已知的实体类,还要根据情况自行设计其他业务类。在此我只设计了一个业务类Data类,用来初始化原始的数据。在根据各个数据关系时,选择了一层层递进的方式,换句话说就是将属性放入ArrayList中在声明在隶属的类中。
在题目中,由于只知道用户操作的ATM编号,以及用户的卡号,于是若想对账号等进行操作,就必须一级一级往上查询。在这里使用了迭代器以及循环,从银联开始一级一级往下遍历匹配,如果匹配成功即将此时的个数据记录下来,也就算是成功查找到用户的信息。
2)第九次作业
圈复杂度:
类图:
分析:第九次的作业实在第八次作业的程度上进行了更深入的研究,在原来的基础上增加了贷记账户,以及跨行收取手续费和贷款时收取手续费。这一次在设计类时,取消了原本用来初始化数据的Data类,而选择将初始化直接放在了Main函数中。设计了WithDraw方法用来具体处理存取款问题,设计了一个Card父类,CreditCard和DebitCard两个实体类继承自它,在两个子类中分别复写不同的具体取款方式,实现程序的多态。
另外,在第八次作业中我们同样遇到了一个棘手的问题,就是已知卡号获取其账户等信息,在上一次的作业中选择了从上往下的查询方式,但这个方法有一定的缺陷,因为若是数据少或许影响不大,但是一旦数据繁多,那么一项项数据去匹配就非常浪费时间以及会导致效率低下。所有在第九次作业中,选择了从下往上双向绑定的方法去寻找。在设计类的属性的时候就将该类所隶属的类设计成该类的属性(比如账户隶属于银行,那么就将银行设计成账户的一种属性),这样在查询卡号的所属信息就可以大大节约时间,提高程序的效率。
(3)踩坑心得
1、在弟八次作业中对查询功能的使用有误,最初在编写代码时,错误的将默认将查询功是放在最后,忽略了在存取款中途查询余额的情况。于是在判断完卡号后接受输入的密码时,判断输入的密码是否是19位或者是“#”,若是19位则代表用户再次输入的是卡号,则再继续至循环开始处,若输入的是“#”则代表用户结束输入,则进行查询后结束程序。
1 if(card.idValidata() == false || flag == 0) { 2 System.out.println("Sorry,this card does not exist."); 3 System.exit(0); 4 } 5 passport = input.next(); 6 if(passport.length() == 19) { 7 System.out.println("¥" + df.format(account.getBalance())); 8 cardNum = passport; 9 continue; 10 } 11 if(passport.equals("#")) { 12 System.out.println("¥" + df.format(account.getBalance())); 13 System.exit(0); 14 }
但是这样的写法仍然是有漏洞的,因为还有其他未考虑周全的地方。
相较于第八次一个数据一个数据的读入,第九次作业选择了一次性将所有数据读入,再将数据按行划分后放入动态数组中,再将动态动态数组中的数据按空格划分成另外一个动态数组存放。这时在判断是否是查询功能的时候只需要判断第二次划分出的动态数组的长度,若数组长度为1,则为查询余额的功能,否则就进行存取款的功能。
1 String[] dt = sb.toString().split("\\n"); 2 for(int i = 0; i < dt.length; i++) { 3 String[] dataLine = dt[i].toString().split("\\\\s+"); 4 5 if(dataLine.length == 1) {//查询 6 GetBalance gb = new GetBalance(unionPay); 7 System.out.println("业务:查询余额 " + String.format("¥%.2f", gb.getBalance(dataLine[0]))); 8 }else { 9 Withdraw wd = new Withdraw(unionPay,dataLine[0],dataLine[1],dataLine[2],Double.parseDouble(dataLine[3])); 10 wd.withdraw(); 11 } 12 }
2、在第九次作业中由于增加了跨行收费以及贷款收费,且贷款透支金额最大为50000,于是编写代码的过程中,疏忽了一种较为极端的情况。当用户贷款加手续费刚好等于50000时,若用户还进行了跨行取款,这时就无法进行取款,解决方法就是在CreditCard的取款判断中多加一个判断是不是有跨行手续费且超支的情况,使得程序更加严谨
(4)改进建议
在这两次的作业中都反映出了一个问题,在判断所有情况时总是不能一次性将所有情况都判断出来,常常会考虑得不够周全,甚至有的时候会为了一时的方便去简化一些小步骤。在日后得学习中不仅编写程序要尽量做好思虑周全,在学习生活中也要思虑周全。
二、总结
通过这三次的作业,收获颇多。四道题目,两种类型。第一个图形面积的处理,更加熟悉了ArrayList工具类的使用,以及熟悉了Comparable和Comparator的功能以及区别和二者的优劣势。以及两道题中都考察到了复写,使得对代码的多态理解的更加清晰了。在第九次作业中,学会了双向绑定的方法,在很大程度上提高了程序的效率。在日后的学习中,要多熟悉熟悉泛化相关的知识,毕竟目前对这方面还不是很熟练,还有要对思考的问题更加细心,尽量一次性考虑到更多可能出现的情况。
以上是关于OO题目集4-6总结的主要内容,如果未能解决你的问题,请参考以下文章