#面向对象程序设计PTA作业# 第4、5、6次作业总结(二)
本篇承接 #面向对象程序设计PTA作业# 第4、5、6次作业总结(一)继续分析题目集4的第5、6题
一、前言
本次总结涉及题目集4的7-1、题目集5的7-5、7-6,题目集6的7-1、7-4、7-5。
1. 三次题目集涉及的的知识点:
- 面向对象技术特性之封装性、字符串处理(4:7-1)
- 面向对象程序设计方法之聚合(5:7-5,7-6)
- 面向对象程序设计之继承(6:7-4,7-5)
2. 题量、难度情况
这三次题目集的题量和难度对于我来说比较大,是我第一次真真切切感受到,软件工程专业的作业不熬几个大夜根本写不完。难度有高有低,跨度还是很明显的,简单题一拿到手里就有思路可以着手来写,但是复杂题往往拿到手里没有什么思路,一方面复杂题(比如6:7-4)的需求就很复杂,阅读量也比较大,需要多读几遍题才能理解需求,另一方面复杂题代码量比较大,编码过程本身就比较耗时,在长达五六个小时的编码过程中还需要时刻注意遵循需求,因此复杂题对我而言还是比较困难。
二、设计与分析
(一)题目及代码
题目集4:7-5
题目7-5
7-5 日期问题面向对象设计(聚合一) 分数 50 作者 段喜龙 单位 南昌航空大学 参考题目7-2的要求,设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1900,2050] ,month∈[1,12] ,day∈[1,31] , 设计类图如下:应用程序共测试三个功能:
求下n天
求前n天
求两个日期相差的天数
注意:严禁使用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
代码长度限制
16 KB
时间限制
10000 ms
内存限制
64 MB
提交代码
import java.util.*; public class Main {public static void main(String[] args) { Scanner input = new Scanner(System.in); int choose = input.nextInt(); /** * 记录两个日期 */ int y1 = 0, m1 = 0, d1 = 0; int y2 = 0, m2 = 0, d2 = 0; DateUtil du1,du2; Day day1 = new Day(); Day day2 = new Day(); Month month1 = new Month(); Month month2 = new Month(); Year year1 = new Year(); Year year2 = new Year(); /** * 记录选择 */ if(choose == 1){ y1 = input.nextInt();m1 = input.nextInt();d1 = input.nextInt();// 接受数据 day1.setValue(d1);month1.setValue(m1);year1.setValue(y1);// 把数据赋值给年月日的属性 month1.setYear(year1);day1.setMonth(month1);// 将对象嵌套好 du1 = new DateUtil();// 创建类 du1.setDay(day1);// 把嵌套好的day1指针赋值给du1的day属性 int n = input.nextInt(); if(du1.checkInputValidity() && n > 0){ System.out.println(du1.getNextDays(n).showDate()); }else{ System.out.print("Wrong Format\n"); } }else if(choose == 2){ y1 = input.nextInt();m1 = input.nextInt();d1 = input.nextInt();// 接受数据 day1.setValue(d1);month1.setValue(m1);year1.setValue(y1);// 把数据赋值给年月日的属性 month1.setYear(year1);day1.setMonth(month1);// 将对象嵌套好 du1 = new DateUtil();// 创建类 du1.setDay(day1);// 把嵌套好的day1指针赋值给du1的day属性 int n = input.nextInt(); if(du1.checkInputValidity() && n > 0){ System.out.println(du1.getPreviousDays(n).showDate()); }else{ System.out.print("Wrong Format\n"); } }else if(choose == 3){ y1 = input.nextInt();m1 = input.nextInt();d1 = input.nextInt(); y2 = input.nextInt();m2 = input.nextInt();d2 = input.nextInt(); day1.setValue(d1);month1.setValue(m1);year1.setValue(y1);// 把数据赋值给年月日的属性 day2.setValue(d2);month2.setValue(m2);year2.setValue(y2);// 把数据赋值给年月日的属性 month1.setYear(year1);day1.setMonth(month1);// 将对象嵌套好 month2.setYear(year2);day2.setMonth(month2);// 将对象嵌套好 du1 = new DateUtil();// 创建日期对象 du2 = new DateUtil(); du1.setDay(day1);// 嵌套体交付 du2.setDay(day2); int result = du2.DaysofDays(du1); if(result != -1){ System.out.println(result); }else{ System.out.print("Wrong Format\n"); } }else{ System.out.print("Wrong Format\n"); } }}
class Year{
int value;
Year(){} /** *带参构造 */ Year(int value){ setValue(value); } /** * 年份加1 */ void yearIncrement(){ this.value++; } /** * 年份减1 */ void yearReduction(){ this.value--; } /** * 判断闰年 */ boolean isLeapYear(){ boolean result = false; if(this.value % 4 == 0 && this.value % 100 != 0 || this.value % 400 == 0){ result = true; } return result; } /** * 判断数据合法性 */ boolean validate(){ boolean result = true; if(this.value > 2050 || this.value < 1900){ result = false; } return result; } public int getValue() { return value; } public void setValue(int value) { this.value = value; }}
class Month{
int value;Year year; /** * 带参构造 */ public Month(int yearValue, int monthValue) { this.value = monthValue; this.year.setValue(yearValue) ; } Month() { } /** * 月份加一 */ void monthIncrement(){ this.value++; if(this.value >= 13){ this.value = 1; this.year.yearIncrement(); } } /** * 月份减一 */ void monthReduction(){ this.value--; if(this.value < 1){ this.value = 12; this.year.yearReduction(); } } /** * 判断合法 */ boolean validate(){ boolean result = false; if(this.year.validate() && this.value > 0 && this.value <= 12){ result = true; } return result; } /** * 月份复位12 */ void resetMax(){ this.value = 12; } /** * 月份复位1 */ void resetMin(){ this.value = 1; } 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; }}
class Day {
int value;
Month month;
int[] mon_maxnum = {31,28,31,30,31,30,31,31,30,31,30,31};/** * 无参构造 */ Day(){ } /** * 带参构造方法 */ Day(int yearValue,int monthValue,int dayValue){ this.value = dayValue; this.month.value = monthValue; this.month.year.value = yearValue; } /** * 复位1 */ void resetMin(){ this.value = 1; } /** * 改为月最大值 */ void resetMax(){ this.value = mon_maxnum[getMonth().getValue()-1]; if(getMonth().getYear().isLeapYear() && getMonth().getValue() == 2){ this.value = 29; } } /** *数据合法性校验 */ boolean validate(){ boolean result = false; if(getMonth().getValue() < 1 || getMonth().getValue() > 12){ result = false; }else if(!getMonth().getYear().isLeapYear() && getMonth().getYear().validate() && getMonth().validate() && this.getValue() > 0 && this.getValue() <= mon_maxnum[getMonth().getValue()-1]){ result = true; }else if(getMonth().getYear().isLeapYear() && getMonth().getValue() == 2 && this.getValue() >0 && this.getValue() <= 29){ result = true; }else if(getMonth().getYear().isLeapYear() && this.getValue() >0 && this.getValue() <= mon_maxnum[getMonth().getValue()-1]){ result = true; } return result; } /** * 日期加一 */ void dayIncrement(){ this.value++; if(!getMonth().getYear().isLeapYear() && getValue() > mon_maxnum[getMonth().getValue()-1]){ getMonth().monthIncrement(); resetMin(); }else if(getMonth().getYear().isLeapYear() && this.getValue() > mon_maxnum[getMonth().getValue()-1]+1 && getMonth().getValue() == 2){ getMonth().monthIncrement(); resetMin(); }else if(getMonth().getYear().isLeapYear() && this.getValue() > mon_maxnum[getMonth().getValue()-1] && getMonth().getValue() != 2){ getMonth().monthIncrement(); resetMin(); } } /** * 日期减一 */ void dayReduction(){ this.value--; if(getValue() < 1){ getMonth().monthReduction(); resetMax(); } } public int getValue() { return value; } public void setValue(int value) { this.value = value; } public Month getMonth() { return month; } public void setMonth(Month month) { this.month = month; }}
class DateUtil{
Day day = new Day();
DateUtil(){// 无参构造方法} /** * 带参构造 */ DateUtil(int day, int month ,int year){ getDay().getMonth().getYear().setValue(year); getDay().getMonth().setValue(month); getDay().setValue(day); } /** * 校验合法性 */ boolean checkInputValidity(){ boolean result = false; if(getDay().validate()){ result = true; } return result; } /** * 比较日期大小,参数日期小则返回true */ boolean compareDates(DateUtil date){ boolean result = false; if(this.getDay().getMonth().getYear().getValue() > date.getDay().getMonth().getYear().getValue()){ result = true; }else if(getDay().getMonth().getYear().getValue() == date.getDay().getMonth().getYear().getValue() && getDay().getMonth().getValue() > date.getDay().getMonth().getValue()){ result = true; }else if(getDay().getMonth().getYear().getValue() == date.getDay().getMonth().getYear().getValue() && getDay().getMonth().getValue() == date.getDay().getMonth().getValue() && getDay().getValue() > date.getDay().getValue()){ result = true; } return result; } /** * 比较两个日期是否相等 */ boolean equalTowDates(DateUtil date){ boolean result = false; if(getDay().getValue() == date.getDay().getValue() && this.getDay().getMonth().getValue() == date.getDay().getMonth().getValue() && this.getDay().getMonth().getYear().getValue() == date.getDay().getMonth().getYear().getValue()){ result = true; } return result; } /** *日期格式化 */ String showDate(){ return (this.getDay().getMonth().getYear().getValue()+"-"+this.getDay().getMonth().getValue()+"-"+this.getDay().getValue()); } /** *求下n天 */ DateUtil getNextDays(int n){ DateUtil date1 = this; for(int i = 0 ; i < n;i++){ date1.getDay().dayIncrement(); } return date1; } /** *求前n天 */ DateUtil getPreviousDays(int n){ DateUtil date1 = this; for(int i = 0 ; i < n;i++){ date1.getDay().dayReduction(); } return date1; } /** *求间隔 */ int DaysofDays(DateUtil date) { int i = 0; if(!this.checkInputValidity() || !date.checkInputValidity()){ i = -1;// 不合法返回-1 } else if (compareDates(date)) { while (!this.equalTowDates(date)) { getDay().dayReduction(); i++; } } else { while (!this.equalTowDates(date)) { getDay().dayIncrement(); i++; } } return i; } public Day getDay() { return day; } public void setDay(Day day) { this.day = day; }
}
题目集4:7-6
题目7-6
7-6 日期问题面向对象设计(聚合二) 分数 34 作者 段喜龙 单位 南昌航空大学 参考题目7-3的要求,设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1820,2020] ,month∈[1,12] ,day∈[1,31] , 设计类图如下:应用程序共测试三个功能:
求下n天
求前n天
求两个日期相差的天数
注意:严禁使用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
代码长度限制
16 KB
时间限制
10000 ms
内存限制
64 MB
提交代码
import java.util.*; public class Main {public static void main(String[] args) { Scanner input = new Scanner(System.in); Day day1 = new Day(); Day day2 = new Day(); Month month1 = new Month(); Month month2 = new Month(); Year year1 = new Year(); Year year2 = new Year(); int choose = input.nextInt(); /** * 记录两个日期 */ int y1 = 0, m1 = 0, d1 = 0; int y2 = 0, m2 = 0, d2 = 0; DateUtil du1,du2; /** * 记录选择 */ if(choose == 1){ y1 = input.nextInt();m1 = input.nextInt();d1 = input.nextInt(); day1.setValue(d1);month1.setValue(m1);year1.setValue(y1); du1 = new DateUtil(day1,month1,year1); int n = input.nextInt(); if(du1.checkInputValidity() && n >= 0){ System.out.println(du1.showDate()+" next "+ n + " days is:" +du1.getNextDays(n).showDate()); }else{ System.out.print("Wrong Format\n"); } }else if(choose == 2){ y1 = input.nextInt();m1 = input.nextInt();d1 = input.nextInt(); day1.setValue(d1);month1.setValue(m1);year1.setValue(y1); du1 = new DateUtil(day1,month1,year1); int n = input.nextInt();// n作为参数 if(du1.checkInputValidity() && n >= 0){ System.out.println(du1.showDate() + " previous " + n +" days is:"+du1.getPreviousDays(n).showDate()); }else{ System.out.print("Wrong Format\n"); } }else if(choose == 3){ y1 = input.nextInt();m1 = input.nextInt();d1 = input.nextInt(); y2 = input.nextInt();m2 = input.nextInt();d2 = input.nextInt(); day1.setValue(d1);month1.setValue(m1);year1.setValue(y1); day2.setValue(d2);month2.setValue(m2);year2.setValue(y2); du1 = new DateUtil(day1,month1,year1); du2 = new DateUtil(day2,month2,year2); String source = du1.showDate(); String last = du2.showDate(); int result = du2.DaysofDays(du1); if(result != -1){ System.out.println("The days between "+source+" and "+ last+" are:"+result); }else{ System.out.print("Wrong Format\n"); } }else{ System.out.print("Wrong Format\n"); } }}
class Year{
int value;
Year(){} /** *带参构造 */ Year(int value){ setValue(value); } /** * 年份加1 */ void yearIncrement(){ this.value++; } /** * 年份减1 */ void yearReduction(){ this.value--; } /** * 判断闰年 */ boolean isLeapYear(){ boolean result = false; if(this.value % 4 == 0 && this.value % 100 != 0 || this.value % 400 == 0){ result = true; } return result; } /** * 判断数据合法性 */ boolean validate(){ boolean result = true; if(this.value > 2020 || this.value < 1820){ result = false; } return result; } public int getValue() { return value; } public void setValue(int value) { this.value = value; }}
class Month{
int value;
/**
* 带参构造
*/
public Month(int Value) {
this.value = Value;
}Month() { } /** * 月份加一 */ void monthIncrement(){ this.value++; } /** * 月份减一 */ void monthReduction(){ this.value--; } /** * 判断合法 */ boolean validate(){ boolean result = false; if(this.value > 0 && this.value <= 12){ result = true; } return result; } /** * 月份复位12 */ void resetMax(){ this.value = 12; } /** * 月份复位1 */ void resetMin(){ this.value = 1; } public int getValue() { return value; } public void setValue(int value) { this.value = value; }}
class Day {
int value;
/**
* 无参构造
*/
Day(){} /** * 带参构造方法 */ Day(int Value){ this.value = Value; } /** * 日期加一 */ void dayIncrement(){ this.value++; } /** * 日期减一 */ void dayReduction(){ this.value--; } public int getValue() { return value; } public void setValue(int value) { this.value = value; }}
class DateUtil{
Day day;
Month month;
Year year;int[] mon_maxnum = {31,28,31,30,31,30,31,31,30,31,30,31}; DateUtil(){// 无参构造方法 } /** * 带参构造 */ DateUtil(Day d, Month m ,Year y){ setDay(d); setMonth(m); setYear(y); } /** * 校验合法性 */ boolean checkInputValidity(){ boolean result = true; if (!getYear().validate() || !getMonth().validate()){ result = false; }else{ if (getYear().isLeapYear() && getMonth().getValue() == 2 && getDay().getValue() > 29 || getDay().getValue() <= 0){ result = false; }else if(getDay().getValue() > mon_maxnum[getMonth().getValue()-1] || getDay().getValue() <=0){ result = false; } } return result; } /** * 比较日期大小,参数日期小则返回true */ boolean compareDates(DateUtil date){ boolean result = false; if(getYear().getValue() > date.getYear().getValue()){ result = true; }else if(getYear().getValue() == date.getYear().getValue() && getMonth().getValue() > date.getMonth().getValue()){ result = true; }else if(getYear().getValue() == date.getYear().getValue() && getMonth().getValue() == date.getMonth().getValue() && getDay().getValue() > date.getDay().getValue()){ result = true; } return result; } /** *日期格式化 */ String showDate(){ return (getYear().getValue()+"-"+getMonth().getValue()+"-"+getDay().getValue()); } /** *求下n天 */ DateUtil getNextDays(int n){ DateUtil date1 = new DateUtil(getDay(), getMonth(), getYear()); int N = n; for(int i = 0 ; i < N;i++){ if (getYear().isLeapYear()){ mon_maxnum[1] = 29; }else{ mon_maxnum[1] = 28; } getDay().dayIncrement(); if(getDay().getValue() > mon_maxnum[getMonth().getValue()-1]){ getMonth().monthIncrement(); getDay().setValue(1); if(getMonth().getValue() > 12){ getYear().yearIncrement(); getMonth().resetMin(); } } } return date1; } /** * 比较相等 */ boolean equalTwoDates(DateUtil date){ boolean result = false; if(this.getYear().getValue() == date.getYear().getValue() && this.getMonth().getValue() == date.getMonth().getValue() && this.getDay().getValue() == date.getDay().getValue()){ result = true; } return result; } /** *求前n天 */ DateUtil getPreviousDays(int n){ DateUtil date1 = new DateUtil(getDay(), getMonth(), getYear()); for(int i = 0 ; i < n;i++) { if (getYear().isLeapYear()){ mon_maxnum[1] = 29; }else{ mon_maxnum[1] = 28; } getDay().dayReduction(); if(getDay().getValue() < 1){ getMonth().monthReduction(); if(getMonth().getValue() < 1){ getYear().yearReduction(); getMonth().resetMax(); } getDay().setValue(mon_maxnum[getMonth().getValue()-1]); } } return date1; } /** *求间隔 */ int DaysofDays(DateUtil date) { int i = 0; DateUtil date1 = new DateUtil(getDay(),getMonth(),getYear()); if(!date1.checkInputValidity() || !date.checkInputValidity()){ i = -1;// 不合法返回-1 } else if (date1.compareDates(date)) { while (!date1.equalTwoDates(date)) { date1.getPreviousDays(1); i++; } } else { while (!date1.equalTwoDates(date)) { date1.getNextDays(1); i++; } } return i; } /** * 设置最小值 */ void setDayMin(){ getDay().setValue(1); } /** * 设置最大值 */ void setDayMax() { if (getYear().isLeapYear() && getMonth().getValue() == 2) { getDay().setValue(29); } else { getDay().setValue(mon_maxnum[getMonth().getValue() - 1]); } } public Day getDay() { return day; } public void setDay(Day day) { this.day = day; } 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; }
}
(二)设计思路
- 功能需求:这道题的功能需求十分复杂,需要应对多种输入情况,同时需要考虑各种输入格式或因输入错误导致的异常。
- 性能方面:本题基本不会涉及到代码性能问题,不作考虑
- 可扩展性:日期系列经过多次迭代,虽然题目没有要求使用继承或实现开闭原则,但是表达清晰的注释和类间关系的低耦合性能够让我们在面对同系列的题目时有所参考,因此这里的设计解耦非常重要
- 可测试性:测试数据将由平台给出,需要通过全部测试点,我们只考虑输入格式即可
- 安全性:需要特别注意各种输入异常导致的空指针问题
- 复用性:如果是单例模式,要保证多次连续访问都能得到正确的结果
程序类图如下:
以上程序通过了所有测试点
三、踩坑心得
提交结果:
这道题目的难度对我来说属于偏简单题,在有限时间内可以比较轻松的完成,因为之前做过类似的题目,上一次对闰年的判断应用了大量的if语句,方法圈复杂度很高,并且有很多漏洞。本次作业采用了不同的思路,解决了之前方法圈复杂度极高且正确率低的问题。以下是对这两道题目的一些思考。
- “聚合”和“组合”在定义上泾渭分明,但在实际编码实现时,可能会搞混,把聚合写成组合,或把组合写成聚合。
四、改进建议
-
命名规范:变量名、函数名、类名等要使用有意义的名称,遵循命名规范,使代码易于理解和维护。
-
代码可复用性:本题由于不侧重要求代码复用,因此本题代码没有实现代码复用性,这两道题目有明显的继承关系,可以考虑通过继承等方式实现代码复用。
-
耦合度:本题大量使用依赖,类间耦合度高,可以拆分职责降低耦合度
五、总结
通过这次题目集,学会了比较灵活的使用正则表达式,掌握了字符串处理中的一大利器。






浙公网安备 33010602011771号