前言:一步错步步错,学习这个循环渐进的过程任何跳步骤的行为都会导致严重的后果。从题目集4开始我就进入了一个非要痛彻心扉改过不可的循环,一个发现困难——放弃——成绩不能达标——发现困难的循环。从题目集4开始题目难度就明显上升,其中的题目1就好像是突然把小坡的坡度加高到小山(这种感觉没错,后来我发现这一题和求日期一样是一个迭代的问题,而我们前面的两次迭代都没有参与,题目集4的题目1是第三次迭代),我光是看到那长长的题目描述就心生退意,更别说后面的题目也并非很容易就能写出,最后这一题被我完全放弃。但是,报应不爽,在题目集6它又来了,它披坚执锐,比前面更难对付,而我前面与它未曾打过交道,更是难以找到破除它防御的方法。情况已经很危急了。
这三次题目集开始我们小试牛刀,感受面向对象编程的一大特性:封装,自此之后,Java与c语言的不同更加明显,一道题不再是一个Main方法可以写出来的了;练习聚合组合的用法,即便一道题目两种写法同是聚合,两者也有相当大的差别;也学习使用了正则表达式,正则表达式不仅在Java里面存在,还存在在好几种语言中,不管是linux,python,c++都可以使用,学会它与我们来说非常必要,是需要花时间去理解和简单记忆的。
在题量方面,这三次题目集的题目都不多,特别是第六次,更是只有一题;但是题目的难度和题量成反比,因为我的日期类题目都写出来了,正则表达式类题目只要找到诀窍,题目都是一样的写法,我自我感觉第四次和第六次题目非常难。
设计和分析:
题目集4的7-1
诚恳地,抱歉地说,我这道题是没怎么写的,因为题目集6的7-1是它的迭代,我的分析就不在这里赘述,都在下面的题目集6的7-1。
题目集5的7-5
7-5 日期问题面向对象设计(聚合一)
分数 50
全屏浏览题目
作者 段喜龙
单位 南昌航空大学
参考题目7-2的要求,设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1900,2050] ,month∈[1,12] ,day∈[1,31] , 设计类图如下:
应用程序共测试三个功能:
- 求下n天
- 求前n天
- 求两个日期相差的天数
输入格式:
有三种输入方式(以输入的第一个数字划分[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 import java.util.Scanner; 2 3 public class Main { 4 public static void main(String[] args) { 5 Scanner input = new Scanner(System.in); 6 int year = 0; 7 int month = 0; 8 int day = 0; 9 10 int choice = input.nextInt(); 11 12 if (choice == 1) { // test getNextNDays method 13 int m = 0; 14 year = Integer.parseInt(input.next()); 15 month = Integer.parseInt(input.next()); 16 day = Integer.parseInt(input.next()); 17 18 DateUtil date = new DateUtil(year, month, day); 19 20 if (!date.checkInputValidity()) { 21 System.out.println("Wrong Format"); 22 System.exit(0); 23 } 24 25 m = input.nextInt(); 26 27 if (m < 0) { 28 System.out.println("Wrong Format"); 29 System.exit(0); 30 } 31 32 System.out.println(date.getNextNDays(m).showDate()); 33 } else if (choice == 2) { // test getPreviousNDays method 34 int n = 0; 35 year = Integer.parseInt(input.next()); 36 month = Integer.parseInt(input.next()); 37 day = Integer.parseInt(input.next()); 38 39 DateUtil date = new DateUtil(year, month, day); 40 41 if (!date.checkInputValidity()) { 42 System.out.println("Wrong Format"); 43 System.exit(0); 44 } 45 46 n = input.nextInt(); 47 48 if (n < 0) { 49 System.out.println("Wrong Format"); 50 System.exit(0); 51 } 52 53 System.out.println(date.getPreviousNDays(n).showDate()); 54 } else if (choice == 3) { //test getDaysofDates method 55 year = Integer.parseInt(input.next()); 56 month = Integer.parseInt(input.next()); 57 day = Integer.parseInt(input.next()); 58 59 int anotherYear = Integer.parseInt(input.next()); 60 int anotherMonth = Integer.parseInt(input.next()); 61 int anotherDay = Integer.parseInt(input.next()); 62 63 DateUtil fromDate = new DateUtil(year, month, day); 64 DateUtil toDate = new DateUtil(anotherYear, anotherMonth, anotherDay); 65 66 if (fromDate.checkInputValidity() && toDate.checkInputValidity()) { 67 System.out.println( fromDate.getDaysofDates(toDate)); 68 } else { 69 System.out.println("Wrong Format"); 70 System.exit(0); 71 } 72 } 73 else{ 74 System.out.println("Wrong Format"); 75 System.exit(0); 76 } 77 } 78 } 79 80 class DateUtil{ 81 private Day day = new Day(); 82 public DateUtil(){ 83 84 } 85 public DateUtil(int d,int m, int y){ 86 int t = 0; 87 t = d; 88 d = y; 89 y = t; 90 this.getDay().setValue(d); 91 this.day.getMonth().setValue(m); 92 this.day.getMonth().getYear().setValue(y); 93 } 94 //day getter 95 public Day getDay() { 96 return day; 97 } 98 //day setter 99 public void setDay(Day d) { 100 this.day = d; 101 } 102 //date校验数据合法性 103 public boolean checkInputValidity(){ 104 return (this.day.getMonth().getYear().validate() && this.day.getMonth().validate() && this.day.validate()); 105 } 106 //比较两个日期的大小 107 public boolean compareDates(DateUtil date){//前一个日期在前正确 108 if(this.day.getMonth().getYear().getValue() - date.day.getMonth().getYear().getValue() > 0){//先判断年份 109 return false; 110 }else if(this.day.getMonth().getYear().getValue() - date.day.getMonth().getYear().getValue() < 0){ 111 return true; 112 }else if(this.day.getMonth().getYear().getValue() - date.day.getMonth().getYear().getValue() == 0){//年份相同的情况下 113 if(this.day.getMonth().getValue() - date.day.getMonth().getValue() > 0){//再判断月份 114 return false; 115 }else if(this.day.getMonth().getValue() - date.day.getMonth().getValue() < 0){ 116 return true; 117 }else //月份相同的情况下 118 if(this.day.getMonth().getValue() - date.day.getMonth().getValue() == 0) 119 if (this.day.getValue() - date.day.getValue() > 0) {//最后判断日子 120 return false; 121 } else if (this.day.getValue() - date.day.getValue() < 0) { 122 return true; 123 } 124 } 125 return true; 126 } 127 //判定两个日期是否相等 128 public boolean equalTwoDates(DateUtil date){//年,月,日一一对应正确 129 return this.day.getMonth().getYear().getValue() == date.day.getMonth().getYear().getValue() && this.day.getMonth().getValue() == date.day.getMonth().getValue() && this.day.getValue() == date.day.getValue(); 130 } 131 //日期值格式化 132 public String showDate(){ 133 return (this.day.getMonth().getYear().getValue() + "-" + this.day.getMonth().getValue() + "-" + this.day.getValue()); 134 } 135 //求下n天 136 public DateUtil getNextNDays(int n){ 137 //计算当前日期在一年里的第几天 138 int sum = 0,daysum = 0; 139 if (this.day.getMonth().getValue() - 1 == 0){ 140 this.day.getMonth().monthReduction(); 141 } 142 for(int i = 0; i < this.day.getMonth().getValue() - 1; i++){ 143 if(this.day.getMonth().getYear().isLeapYear(this.day.getMonth().getYear().getValue())){ 144 this.day.getMon_maxnum()[1] = 29; 145 }else this.day.getMon_maxnum()[1] = 28; 146 sum += this.day.getMon_maxnum()[i]; 147 } 148 sum += this.day.getValue(); 149 //计算下个日期的年份 150 sum += n; 151 if(this.day.getMonth().getYear().isLeapYear(this.day.getMonth().getYear().getValue())){ 152 daysum = 366; 153 }else{ 154 daysum = 365; 155 } 156 while (sum - daysum > 0){//daysum==0 157 if(this.day.getMonth().getYear().isLeapYear(this.day.getMonth().getYear().getValue())){ 158 daysum = 366; 159 }else{ 160 daysum = 365; 161 } 162 sum = sum-daysum; 163 //this.year ++; 164 this.day.getMonth().getYear().yearIncrement(); 165 //this.month = 1; 166 this.day.getMonth().resetMin(); 167 } 168 if(this.day.getMonth().getYear().isLeapYear(this.day.getMonth().getYear().getValue())){ 169 this.day.getMon_maxnum()[1] = 29; 170 }else{ 171 this.day.getMon_maxnum()[1] = 28; 172 } 173 //sum是月与日 174 if(sum > this.day.getMon_maxnum()[0]) {//计算月日 175 for (int i = 0; sum > this.day.getMon_maxnum()[i]; i++) { 176 sum = sum - this.day.getMon_maxnum()[i]; 177 this.day.getMonth().setValue(i); 178 } 179 this.day.getMonth().monthIncrement(); 180 } 181 this.day.setValue(sum); 182 this.day.getMonth().monthIncrement(); 183 return this; 184 } 185 //求前n天 186 public DateUtil getPreviousNDays(int n){ 187 //计算当前日期在一年里的第几天 188 int sum = 0,daysum = 0; 189 for(int i = 0; i < this.day.getMonth().getValue() - 1; i ++){ 190 if(this.day.getMonth().getYear().isLeapYear(this.day.getMonth().getYear().getValue())){ 191 this.day.getMon_maxnum()[1] = 29; 192 }else this.day.getMon_maxnum()[1] = 28; 193 sum += this.day.getMon_maxnum()[i]; 194 } 195 sum += this.day.getValue(); 196 //计算下一个日期 197 sum -= n; 198 if(sum<0){//跨年了 199 if(this.day.getMonth().getYear().isLeapYear(this.day.getMonth().getYear().getValue()-1)){ 200 daysum = 366; 201 }else{ 202 daysum = 365; 203 }//计算年份 204 while (sum+daysum<0){ 205 if(this.day.getMonth().getYear().isLeapYear(this.day.getMonth().getYear().getValue()-1)){ 206 daysum = 366; 207 }else{ 208 daysum = 365; 209 } 210 sum = sum+daysum; 211 this.day.getMonth().getYear().yearReduction(); 212 }//计算正数的月份 213 //this.year = this.year-1; 214 this.day.getMonth().getYear().yearReduction(); 215 if(this.day.getMonth().getYear().isLeapYear(this.day.getMonth().getYear().getValue())){ 216 daysum = 366; 217 }else{ 218 daysum = 365; 219 } 220 sum = daysum+sum; 221 } 222 if(this.day.getMonth().getYear().isLeapYear(this.day.getMonth().getYear().getValue())){ 223 this.day.getMon_maxnum()[1] = 29; 224 }else{ 225 this.day.getMon_maxnum()[1] = 28; 226 } 227 //计算月份 228 if(sum > this.day.getMon_maxnum()[0]) {//计算月日 229 for (int i = 0; sum > this.day.getMon_maxnum()[i]; i ++) { 230 sum = sum - this.day.getMon_maxnum()[i]; 231 //this.month = i; 232 this.day.getMonth().setValue(i); 233 } 234 this.day.getMonth().monthIncrement(); 235 } 236 this.day.setValue(sum); 237 this.day.getMonth().monthIncrement(); 238 return this; 239 } 240 //求两个日期之间的天数 241 public int getDaysofDates(DateUtil date){ 242 int n = 0; 243 if(equalTwoDates(date)){ 244 return 0; 245 }else { 246 int k = 0; 247 //保证第一个日期始终在前 248 if (!compareDates(date)) { 249 k = this.day.getMonth().getYear().getValue(); 250 this.day.getMonth().getYear().setValue(date.day.getMonth().getYear().getValue()); 251 date.day.getMonth().getYear().setValue(k); 252 k = this.day.getMonth().getValue(); 253 this.day.getMonth().setValue(date.day.getMonth().getValue()); 254 date.day.getMonth().setValue(k); 255 k = this.day.getValue(); 256 this.day.setValue(date.day.getValue()); 257 date.day.setValue(k); 258 } 259 //计算两个日期相差天数 260 //计算两个日期在一年里的位置 261 int sum1 = 0, daysum = 0, sum2 = 0; 262 for (int i = 0; i < this.day.getMonth().getValue() - 1; i ++) { 263 if (this.day.getMonth().getYear().isLeapYear(this.day.getMonth().getYear().getValue())) { 264 this.day.getMon_maxnum()[1] = 29; 265 } 266 else this.day.getMon_maxnum()[1] = 28; 267 sum1 += this.day.getMon_maxnum()[i]; 268 } 269 sum1 += this.day.getValue(); 270 271 for (int i = 0; i < date.day.getMonth().getValue() - 1; i++) { 272 if (this.day.getMonth().getYear().isLeapYear(date.day.getMonth().getYear().getValue())) { 273 this.day.getMon_maxnum()[1] = 29; 274 } 275 else this.day.getMon_maxnum()[1] = 28; 276 sum2 += this.day.getMon_maxnum()[i]; 277 } 278 sum2 += date.day.getValue(); 279 //n = sum2 - sum1;//计算一年里两个日期的差 280 //计算两个日期相差的年份 281 for (; this.day.getMonth().getYear().getValue() <= date.day.getMonth().getYear().getValue();) { 282 n += daysum; 283 if (this.day.getMonth().getYear().isLeapYear(this.day.getMonth().getYear().getValue())) { 284 daysum = 366; 285 } else { 286 daysum = 365; 287 } 288 this.day.getMonth().getYear().yearIncrement(); 289 } 290 n = n - sum1 +sum2; 291 } 292 return n; 293 } 294 } 295 class Day{ 296 private int value; 297 private Month month = new Month(); 298 private int[] mon_maxnum = {31,28,31,30,31,30,31,31,30,31,30,31}; 299 public Day(){ 300 301 } 302 public Day(int yearValue, int monthValue, int dayValue){ 303 this.value = dayValue; 304 this.getMonth().setValue(monthValue); 305 this.month.getYear().setValue(yearValue); 306 } 307 308 public int[] getMon_maxnum() { 309 return mon_maxnum; 310 } 311 312 //day value getter 313 public int getValue() { 314 return value; 315 } 316 //day value setter 317 public void setValue(int value) { 318 this.value = value; 319 } 320 //day month getter 321 public Month getMonth() { 322 return month; 323 } 324 //day month setter 325 public void setMonth(Month value) { 326 this.month = value; 327 } 328 //day 日期复位(1) 329 public void resetMin(){ 330 this.value = 1; 331 } 332 //day 日期设为该月最大值 333 public void resetMax(){ 334 this.value = mon_maxnum[this.month.getValue()]; 335 } 336 //day校验数据合法性 337 public boolean validate(){ 338 if (this.month.getYear().isLeapYear(this.month.getYear().getValue())){ 339 mon_maxnum[1] += 1; 340 } 341 if (this.value > mon_maxnum[this.month.getValue() - 1] || this.value < 1){ 342 return false; 343 }else return true; 344 } 345 //日期增1 346 public void dayIncrement(){ 347 this.value ++; 348 } 349 //日期减1 350 public void dayReduction(){ 351 this.value --; 352 } 353 } 354 class Month{ 355 private int value; 356 private Year year = new Year(); 357 public Month(){ 358 359 } 360 public Month(int yearValue,int monthValue){ 361 this.value = monthValue; 362 this.getYear().setValue(yearValue); 363 } 364 //month value getter 365 public int getValue() { 366 return value; 367 } 368 //month value setter 369 public void setValue(int value) { 370 this.value = value; 371 } 372 //month year getter 373 public Year getYear() { 374 return year; 375 } 376 //month year setter 377 public void setYear(Year year) { 378 this.year = year; 379 } 380 //月份复位(1) 381 public void resetMin(){ 382 this.value = 1; 383 } 384 //月份设置为12 385 public void resetMax(){ 386 this.value = 12; 387 } 388 //month校验数据合法性 389 public boolean validate(){ 390 return (this.value >= 1 && this.value <= 12); 391 } 392 //月份增1 393 public void monthIncrement(){ 394 this.value ++; 395 } 396 //月份减1 397 public void monthReduction(){ 398 this.value --; 399 } 400 } 401 class Year{ 402 private int value; 403 public Year(){ 404 405 } 406 public Year(int value){ 407 this.value = value; 408 } 409 //year value getter 410 public int getValue() { 411 return value; 412 } 413 //year value setter 414 public void setValue(int value) { 415 this.value = value; 416 } 417 //判断是否为闰年 418 public boolean isLeapYear(int value){ 419 return ((value % 400 == 0) || (value % 4 == 0 && value % 100 != 0)); 420 } 421 //year校验数据合法性 422 public boolean validate(){ 423 return (this.value >= 1900 && this.value <= 2050); 424 } 425 //年份增1 426 public void yearIncrement(){ 427 this.value ++; 428 } 429 //年份减1 430 public void yearReduction(){ 431 this.value --; 432 } 433 }
用PowerDesigner生成的图像:
用SourceMonitor生成图像:
分析:设计类图老师已经交给了我们,这题需要我们定义四个类,和上一次迭代相比,DateUtil不再做所有的工作,而是把工作分给了新类Day,Month,Year,比如判断是否为闰年的方法isLeapYear()成为Year类独有的,加一天减一天dayIncrement(),dayReduction()这样的小代码也被独立出来成为一个方法在Day类里面,这么做是为了实现单一职责原则,让Main类和DataUtil类不要做太多事,达成容易找到错误,代码易修改的成就,如果一个代码块过长,功能过多,代码的方法就像海藻一样纠缠在一起就不容易查找bug,找到后也很难去修改,后期难以维护,如果将代码块截成一个一个小块,使用的时候用统一的引用方法(例如date.getDay()),那么假使真的代码有错,只要修改小代码块的部分就可以,所有的引用(date.getDay())是不用动的,比不按这种方法写就得查找每一行代码看是否有错要来得轻松的多。说完聚合的好处,再说怎么样实现聚合。在DateUtil类里面有Day属性,在Day类里面有Month属性,在Month类里面有Year属性。也就是说Month可以调用Year里面的方法,Day可以调用Month里面的方法,DateUtil可以调用Day里面的方法,主方法与DateUtil联系紧密,它们形成了一条调用方法的链,按照这个类图的特性来说类图里面两个类只要间隔一个类那么它们就不能直接沟通,前面的不能直接调用后面的方法,只有通过中间的类辅助才可以,也就是说如果在主方法里面需要判断一年是否是闰年,用到Year类的isLeapYear方法,直接写isLeapYear(某年)是不可行的,而应该要在Main类里面定义一个DateUtil属性的date;再写date.getDay().getMonth().getYear().isLeapYear(某年)才可以,当然这是例子,实际上Main类根本就不会用到isLeapYear()方法,为了落实单一职责,它只会引用到DateUtil的showDate()方法,具体有关时间的计算,各种调用还是在DateUtil类里实现的,应该说除了处于最底层的Year类,其他几个类都会或多或少实现调用。
从我自己的代码生成的类图分析:
我不清楚是类图生成有误还是什么,我的类图把聚合关系变成了关联,按理说聚合的实现方法就是在一个类里面私有化另一个类对象,加诸另一个类的setter和getter方法,以setter和getter方法为媒介使一个类可以通过该私有化对象调用另一个类的方法,而我就是这样写的,却没得到聚合的结果。不过,链式结构是没错的。因为有老师的类图指导,结果和老师的类图也类似。
从SourceMonitor来看,我的代码还是那些问题,毕竟也就是之前写过了的日期类题目稍加改动得到的,我的代码Max Complexity超过绿色区域,Avg Complexity却不在绿色范围内,应该是给DateUtil类的任务太重了,导致DateUtil的圈复杂度非常大,if-else语句太多了。
题目集5的7-6
题目如下:
7-6 日期问题面向对象设计(聚合二) 分数 34 作者 段喜龙 单位 南昌航空大学参考题目7-3的要求,设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1820,2020] ,month∈[1,12] ,day∈[1,31] , 设计类图如下:
应用程序共测试三个功能:
- 求下n天
- 求前n天
- 求两个日期相差的天数
我的代码如下:
1 import java.util.Scanner; 2 public class Main { 3 public static void main(String[] args) { 4 Scanner input = new Scanner(System.in); 5 int year = 0; 6 int month = 0; 7 int day = 0; 8 9 int choice = input.nextInt(); 10 11 if (choice == 1) { // test getNextNDays method 12 int m = 0; 13 year = Integer.parseInt(input.next()); 14 month = Integer.parseInt(input.next()); 15 day = Integer.parseInt(input.next()); 16 17 DateUtil date = new DateUtil(year, month, day); 18 19 if (!date.checkInputValidity()) { 20 System.out.println("Wrong Format"); 21 System.exit(0); 22 } 23 24 m = input.nextInt(); 25 26 if (m < 0) { 27 System.out.println("Wrong Format"); 28 System.exit(0); 29 } 30 31 System.out.print(date.getYear().getValue() + "-" + date.getMonth().getValue() + "-" + date.getDay().getValue() + " next " + m + " days is:"); 32 System.out.println(date.getNextNDays(m).showDate()); 33 } else if (choice == 2) { // test getPreviousNDays method 34 int n = 0; 35 year = Integer.parseInt(input.next()); 36 month = Integer.parseInt(input.next()); 37 day = Integer.parseInt(input.next()); 38 39 DateUtil date = new DateUtil(year, month, day); 40 41 if (!date.checkInputValidity()) { 42 System.out.println("Wrong Format"); 43 System.exit(0); 44 } 45 46 n = input.nextInt(); 47 48 if (n < 0) { 49 System.out.println("Wrong Format"); 50 System.exit(0); 51 } 52 53 System.out.print(date.getYear().getValue() + "-" + date.getMonth().getValue() + "-" + date.getDay().getValue() + " previous " + n + " days is:"); 54 System.out.println(date.getPreviousNDays(n).showDate()); 55 } else if (choice == 3) { //test getDaysofDates method 56 year = Integer.parseInt(input.next()); 57 month = Integer.parseInt(input.next()); 58 day = Integer.parseInt(input.next()); 59 60 int anotherYear = Integer.parseInt(input.next()); 61 int anotherMonth = Integer.parseInt(input.next()); 62 int anotherDay = Integer.parseInt(input.next()); 63 64 DateUtil fromDate = new DateUtil(year, month, day); 65 DateUtil toDate = new DateUtil(anotherYear, anotherMonth, anotherDay); 66 67 if (fromDate.checkInputValidity() && toDate.checkInputValidity()) { 68 System.out.println("The days between " + fromDate.showDate() + 69 " and " + toDate.showDate() + " are:" 70 + fromDate.getDaysofDates(toDate)); 71 } else { 72 System.out.println("Wrong Format"); 73 System.exit(0); 74 } 75 } 76 else{ 77 System.out.println("Wrong Format"); 78 System.exit(0); 79 } 80 } 81 } 82 83 class DateUtil{ 84 private Year year = new Year(); 85 private Month month = new Month(); 86 private Day day = new Day(); 87 private int[] mon_maxnum = {31,28,31,30,31,30,31,31,30,31,30,31}; 88 public DateUtil(){ 89 90 } 91 public DateUtil(int y,int m, int d) { 92 this.getYear().setValue(y); 93 this.getMonth().setValue(m); 94 this.getDay().setValue(d); 95 } 96 public void setYear(Year year) { 97 this.year = year; 98 } 99 100 public Year getYear() { 101 return year; 102 } 103 104 public Month getMonth() { 105 return month; 106 } 107 108 public void setMonth(Month month) { 109 this.month = month; 110 } 111 112 public Day getDay() { 113 return day; 114 } 115 116 public void setDay(Day day) { 117 this.day = day; 118 } 119 //设置日期最小值(1) 120 public void setDayMin(){ 121 int dayMin = 1; 122 } 123 //设置日期最大值(当月最大天数) 124 public void setDayMax(){ 125 int dayMax = this.mon_maxnum[this.getMonth().getValue()]; 126 } 127 //DateUtil校验输入数据合法性 128 public boolean checkInputValidity(){ 129 if (this.getYear().validate() && this.getMonth().validate()){ 130 if(this.getDay().getValue() >= 1 && this.getDay().getValue() <= this.mon_maxnum[this.getMonth().getValue() - 1]){ 131 return true; 132 }else return false; 133 }else return false; 134 } 135 //求下n天 136 public DateUtil getNextNDays(int n){ 137 //计算当前日期在一年里的第几天 138 int sum = 0,daysum = 0; 139 if (this.getMonth().getValue() - 1 == 0){ 140 this.getMonth().monthReduction(); 141 } 142 for(int i = 0; i < this.getMonth().getValue() - 1; i ++){ 143 if(this.getYear().isLeapYear()){ 144 mon_maxnum[1] = 29; 145 }else mon_maxnum[1] = 28; 146 sum += mon_maxnum[i]; 147 } 148 sum += this.getDay().getValue(); 149 //计算下个日期的年份 150 sum += n; 151 if(this.getYear().isLeapYear()){ 152 daysum = 366; 153 }else{ 154 daysum = 365; 155 } 156 while (sum - daysum > 0){//daysum==0 157 if(this.getYear().isLeapYear()){ 158 daysum = 366; 159 }else{ 160 daysum = 365; 161 } 162 sum = sum - daysum; 163 this.getYear().yearIncrement(); 164 this.getMonth().resetMin(); 165 } 166 if(this.getYear().isLeapYear()){ 167 mon_maxnum[1] = 29; 168 }else{ 169 mon_maxnum[1] = 28; 170 } 171 //sum是月与日 172 if(sum>mon_maxnum[0]) {//计算月日 173 for (int i = 0; sum > mon_maxnum[i]; i++) { 174 sum = sum - mon_maxnum[i]; 175 this.getMonth().setValue(i); 176 } 177 this.getMonth().monthIncrement(); 178 } 179 this.getDay().setValue(sum); 180 this.getMonth().monthIncrement(); 181 return this; 182 } 183 //求前n天 184 public DateUtil getPreviousNDays(int n){ 185 //计算当前日期在一年里的第几天 186 int sum = 0,daysum = 0; 187 for(int i = 0; i < this.getMonth().getValue() - 1; i ++){ 188 if(this.getYear().isLeapYear()){ 189 mon_maxnum[1] = 29; 190 }else mon_maxnum[1] = 28; 191 sum += mon_maxnum[i]; 192 } 193 sum += this.getDay().getValue(); 194 //计算下一个日期 195 sum -= n; 196 if(sum<0){//跨年了 197 if(this.getYear().isLeapYear(this.getYear().getValue()-1)){ 198 daysum = 366; 199 }else{ 200 daysum = 365; 201 }//计算年份 202 while (sum+daysum<0){ 203 if(this.getYear().isLeapYear(this.getYear().getValue()-1)){ 204 daysum = 366; 205 }else{ 206 daysum = 365; 207 } 208 sum = sum+daysum; 209 this.getYear().yearReduction(); 210 }//计算正数的月份 211 this.getYear().setValue(this.getYear().getValue()-1); 212 if(this.getYear().isLeapYear()){ 213 daysum = 366; 214 }else{ 215 daysum = 365; 216 } 217 sum = daysum+sum; 218 } 219 if(this.getYear().isLeapYear()){ 220 mon_maxnum[1] = 29; 221 }else{ 222 mon_maxnum[1] = 28; 223 } 224 //计算月份 225 if(sum>mon_maxnum[0]) {//计算月日 226 for (int i = 0; sum > mon_maxnum[i]; i++) { 227 sum = sum - mon_maxnum[i]; 228 //**** 229 this.getMonth().setValue(i); 230 }//**** 231 this.getMonth().monthIncrement(); 232 } 233 this.getDay().setValue(sum); 234 this.getMonth().monthIncrement(); 235 return this; 236 } 237 //判定两个日期的先后 238 public boolean compareDates(DateUtil date){ 239 if(this.getYear().getValue() - date.getYear().getValue() > 0){ 240 return false; 241 }else if(this.getYear().getValue() - date.getYear().getValue() < 0){ 242 return true; 243 }else if(this.getYear().getValue() - date.getYear().getValue() == 0){ 244 if(this.getMonth().getValue() - date.getMonth().getValue() > 0){ 245 return false; 246 }else if(this.getMonth().getValue() - date.getMonth().getValue() < 0){ 247 return true; 248 }else if(this.getMonth().getValue() - date.getMonth().getValue() == 0){ 249 if(this.getDay().getValue() - date.getDay().getValue() > 0){ 250 return false; 251 }else if(this.getDay().getValue() - date.getDay().getValue() < 0){ 252 return true; 253 } 254 } 255 } 256 return true; 257 } 258 //判断两个日期是否相等 259 public boolean equalTwoDates(DateUtil date){ 260 if(this.getYear().getValue() == date.getYear().getValue() && this.getMonth().getValue() == date.getMonth().getValue() && this.getDay().getValue() == date.getDay().getValue()){ 261 return true; 262 }else return false; 263 } 264 //求两个日期的天数差 265 public int getDaysofDates(DateUtil date){ 266 int n = 0; 267 if(equalTwoDates(date)){ 268 return 0; 269 }else { 270 int k = 0; 271 //保证第一个日期始终在前 272 if (!compareDates(date)) { 273 k = this.getYear().getValue(); 274 this.getYear().setValue(date.getYear().getValue()); 275 date.getYear().setValue(k); 276 k = this.getMonth().getValue(); 277 this.getMonth().setValue(date.getMonth().getValue()); 278 date.getMonth().setValue(k); 279 k = this.getDay().getValue(); 280 this.getDay().setValue(date.getDay().getValue()); 281 date.getDay().setValue(k); 282 } 283 //计算两个日期相差天数 284 //计算两个日期在一年里的位置 285 int sum1 = 0, daysum = 0, sum2 = 0; 286 for (int i = 0; i < this.getMonth().getValue() - 1; i ++) { 287 if (this.getYear().isLeapYear()) { 288 mon_maxnum[1] = 29; 289 } 290 else mon_maxnum[1] = 28; 291 sum1 += mon_maxnum[i]; 292 } 293 sum1 += this.getDay().getValue(); 294 295 for (int i = 0; i < date.getMonth().getValue() - 1; i ++) { 296 if (date.getYear().isLeapYear()) { 297 mon_maxnum[1] = 29; 298 } 299 else mon_maxnum[1] = 28; 300 sum2 += mon_maxnum[i]; 301 } 302 sum2 += date.getDay().getValue(); 303 //计算两个日期相差的年份 304 for (; this.getYear().getValue() <= date.getYear().getValue() ;) { 305 n += daysum; 306 if (this.getYear().isLeapYear()) { 307 daysum = 366; 308 } else { 309 daysum = 365; 310 } 311 this.getYear().yearIncrement(); 312 } 313 n = n - sum1 +sum2; 314 } 315 return n; 316 } 317 //日期按年月日格式化 318 public String showDate(){ 319 return (this.getYear().getValue() + "-" + this.getMonth().getValue() + "-" + this.getDay().getValue()); 320 } 321 322 } 323 class Year{ 324 private int value; 325 public Year(){ 326 327 } 328 public Year(int value){ 329 this.value = value; 330 } 331 332 public int getValue() { 333 return value; 334 } 335 336 public void setValue(int value) { 337 this.value = value; 338 } 339 //判断闰年 340 public boolean isLeapYear(){ 341 return ((this.value % 400 ==0) || (this.value % 4 == 0 && this.value % 100 != 0)); 342 } 343 public boolean isLeapYear(int year){ 344 return ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0)); 345 } 346 //year数据合法性校验 347 public boolean validate(){ 348 if(this.value >= 1820 && this.value <= 2020){ 349 return true; 350 }else return false; 351 } 352 //年增1 353 public void yearIncrement(){ 354 this.value ++; 355 } 356 //年减1 357 public void yearReduction(){ 358 this.value --; 359 } 360 } 361 class Month{ 362 private int value; 363 public Month(){ 364 365 } 366 public Month(int value){ 367 this.value = value; 368 } 369 370 public int getValue() { 371 return value; 372 } 373 374 public void setValue(int value) { 375 this.value = value; 376 } 377 //月份复位(1) 378 public void resetMin(){ 379 this.value = 1; 380 } 381 //月份设置最大值(12) 382 public void reseMax(){ 383 this.value = 12; 384 } 385 //month数据合法性校验 386 public boolean validate(){ 387 if(this.value >= 1 && this.value <= 12){ 388 return true; 389 }else return false; 390 } 391 //月增1 392 public void monthIncrement(){ 393 this.value ++; 394 } 395 //月减1 396 public void monthReduction(){ 397 this.value --; 398 } 399 } 400 class Day{ 401 private int value; 402 public Day(){ 403 404 } 405 public Day(int value){ 406 this.value = value; 407 } 408 409 public int getValue() { 410 return value; 411 } 412 413 public void setValue(int value) { 414 this.value = value; 415 } 416 //日增1 417 public void dayIncrement(){ 418 this.value ++; 419 } 420 //日减1 421 public void dayReduction(){ 422 this.value --; 423 } 424 }
它的PowerDesigner图像如下:
它的SourcePointer图像如下:
分析:这题与上一题用到的方法并没有什么不同,但是光从类图的结构的明显不同也可知它们绝不一样,7-5的类图是链式结构,7-6的类图是星形结构。在这一题中DateUtil类作为一个中心体与Day类,Month类,Year类直接接触,也就是说DateUtil类只要在类里面定义Day型day,Month型month,Year型year就可以直接利用day,month,year调用Day类,Month类,Year类里面的方法,调用方法与上一题的分析一致,例如在DateUtil类里面需要判断某年是不是闰年,就可以写day.isLeapYear()。将结构改为这样调用将变得格外简单,上一题想要调用判断是否为闰年这个方法足足要写好长一段,从DateUtil开始要调用Day,Month,Year每一个类,如果是一时还好,可是如果每一次想用方法都写一大长串叫人烦躁,代码的可读性也大大降低,写着写着使人眼花缭乱,容易出错。我私以为第二种聚合方法更加优秀。
从我自己的代码生成的类图分析:
不考虑聚合关系被关联取代的话,我的类图结果也没有什么问题。
从SourceMonitor来说也就是老调重弹了。暂时我对该怎么去改造还没什么想法。
题目集6的7-1
题目因为太长为了避免说是水字数就不放上了。
分析:我不能说自己为了这道题废寝忘食,但是我也不是什么都没写的。当我看到这题时,脑子非常混乱,因为经过几次迭代它变得无比复杂,光是比上一次迭代增加的异常情况就有17个。我只能尽量在那让人眼花缭乱的题目描述里找到这个题目的基本结构和基本思路。老师对我们还是放了水的,读了两遍题我大概知道自己要至少写5个类,一个Main类,一个Dish类,一个Menu类,一个Record类和一个Order类,Menu类和Order类分别包含Dish类和Record类,即Menu类和Dish类是组合关系,Order类和Record类是组合关系。一个Dish类是菜单上的一行信息,一个Record类是订单上的一行信息,根据Menu类里有addDish()方法,Order类里有addRecord()方法可知Menu类和Order类里面的Dish类数组和Record类数组应该是动态数组,不过这个想法是我现在想到的,还未进行验证,我的代码不是这样的,我之前想的是在addDiah()和addRecord()方法里面定义它进行操作的是一个动态数组,即在Menu类属性里面定义Dish是一个普通数组dishs,在addDiah()方法里面重新开辟了一个新空间给动态数组(ArrayList<Dish> dishs = new ArrayList<>()),两个数组的名字是一样的,我期待两者可以交互,但是这样和类本身的数组想来是根本不能进行联系的,想当然,不应该。
题目和时间是过不去了,鉴于订单要根据时间计算折扣和报错,我私以为应该加一个有关时间的类,一开始我定了一个名字DateUtil,后面改为了Date,这个和一次报错有关,我将放在下面的踩坑心得里面介绍。因为这个时间类不是老师给的,有关它的一切都要我自己摸索去设定,从上面介绍的两题我获取经验,我觉得它应该要有属性Day,Month,Year,根据题目还要加上Hour,Minute,Millisecond这三个属性,得要有判断时间是否正确的方法。一开始,我打算把判断数据格式合规和日期合法(时间在正常范围)两者写成一个方法,可是两者的输出是不一样的,放一起有违单一职责的设计原则,而且直接使用Java的自带判断时间是否合法的方法也比较麻烦,网上找到的代码都不能完全符合我的要求,混合对我的改写能力要求太高,再三考虑,我决定将它们分成两个方法。在时间类里还要有有一个方法用来判断时间是否在工作日,这是为了方便进行折扣的相关计算。我那时还暂时不打算考虑后续加餐的情况,于是就写了这几个类。代点餐我也没有考虑,一切都是为了能快速写出一些像样的东西来,可惜我没有得到好结果。现在再思考,时间类应该还要有判断后续桌号相同的点餐与上一次是否在一个小时内的方法,这是加餐了,得算在一个桌的费用里,命名为isSame就不错。
类差不多写完了,到Main类,显然Main类里面要有读取数据并且把它们分开的操作,写一个While循环,按行输入(读取),使用正则表达式,把每一行读到的数据按照人读的方式组成一个数组,在没读到菜单(菜单先)前的数据存入一个新的数组,或者说菜单和订单的每一行信息组成的数组非常特殊,需要存入Dish数组,Record数组,其他信息与它们分开储存。开始时我边读入数据边对它们进行处理(判断),但是报错是有顺序的,不可以即时报错,正确的顺序是先读完所有的数据,再对数据进行处理,再报错,这也是我不能把判断数据格式合规和日期合法(时间在正常范围)两者写成一个方法的原因之一,这两个方法只能是boolean类型,不能是void类型,方法绝不能有输出。那么Main类就要包括所有的输入和输出了。代点餐的判定我之前看了许久不能理解,现在好像可以理解了,输入框在一个小时内是专为一桌顾客服务的,如果加点菜的桌号保持相同,是本桌加餐,如果桌号是不同的,那就是代点餐。还得是输入数据的处理,只要输入的数据分好类,方法写对可行,剩下的事大概就剩各种判断。
踩坑心得:一些题目我没有着重分析,是因为它们还不够难,但是我不是没有在写它们的时候犯错,比如题目集4的7-2有重复的数据,在嵌套循环判断两个数据是否相等的时候,首先我在判定相等后就立马输出NO,在循环结束后输出YES,结果是不论是否发现重复数据我都会输出YES,不符合题意。我那时想来有点昏头,想了许久,才想到使用一个判断常量。如下:
1 for(int i = 0; i < n; i++){ 2 if(i!=0){ 3 if(line[i]==line[i-1]){ 4 flag=1; 5 } 6 } 7 }//循环结束后进行判断 8 if(flag==1){ 9 System.out.print("YES"); 10 } 11 if(flag==0){ 12 System.out.print("NO"); 13 }
如果找到重复数据就改变flag的值,以flag的值判定输出内容。
题目集5上来就给出4个正则表达式的题目作为拦路虎,此前我虽然在学习通上的课里学习了正则表达式,可是正则表达式的用法规则对新手的我来说多如牛毛,在这几题,好几次都是没能运用到正确的字符串分块方法导致结果有误,当然还有其他不熟的特殊字符的用法也使得我的攻题过程难以为继,比如说matches的用法,老师课上没讲,可它在题目里非常实用。matches查找一个字符串是否包含一个特定字符串,并且返回true或false,用在一些需要判断对错的题目里再合适不过。
大概这么用:
1 public static boolean isQualified (String s){ 2 String regStr = "[1-9]\\d{4,14}"; 3 return s.matches(regStr); 4 }
s是输入数据,regStr是要求的输入数据的基本格式。
写日期问题面向对象设计(聚合一)的时候,我看着类图不知道怎么下手,因为在这之前我没有写过在一个类里的属性是另一个类的题目(A类的属性里有B),我惶恐,战战兢兢按照基本步骤,在A类里给出B类的getter,setter方法,然后问题就来了,我该怎么去在A类里用B类的方法呢?也是运气,我在乱敲键盘的时候看见ijidea在我定义的B类对象加一点后(b.Bgetter())自动提示了B类的getter方法(B类的getter,setter方法已经写好),好新奇!我茅塞顿开。应用B类的方法得先用它的getter方法得到它。可是在A类方法里改变B对象的值的时候我又陷入难题,直接b.Bsetter() = *是错的!编译器不给过!那难道还能有别的方法不成?这时我连getter方法的用法都产生了怀疑。最终setter()的括号下的红线拉回了我离真相越来越远的脑洞,我把值(*)放进setter()的括号里(b.Bsettter(*)),果然对了。后面一切顺利。日期问题面向对象设计(聚合二)也是按照类图把一些表达一个一个修改就完成了。
到菜单计价程序-4,我想使用Java自带的判断时间是不是工作日的方法:
public boolean isWeekday(Date date) { //String[] weeks = {"星期日","星期一","星期二","星期三","星期四","星期五","星期六"}; Calendar cal = Calendar.getInstance(); cal.setTime(date); int week_index = cal.get(Calendar.DAY_OF_WEEK) - 1; if(week_index<0){ week_index = 0; } if (week_index == 1 || week_index == 7) { return false; } else { return true; }
但是传入数据Date类型一直报错,我以为是时间类名不相同(我的时间类叫DAteUtil),改后,编译还是报错。后知后觉,我发现Java是有独属于自己的Date类的,程序员可以重新自定义一个,但是传入的数据还是认自带Date类。无法,只有将(Date date )改为(java.util.Date date)。
Menu类里的Dish addDish()方法,我不知道该如何返回一个Dish类,苦思冥想,未果,翻找ArrayList相关内容,发现了.get()方法(return dishs.get(dishs.size()))。
改进建议:简单题目代码长度太短,都谈不上改进,难一点的题是日期类问题和菜单计价程序问题,前者的圈复杂度太大让人诟病,需要减少循环的数量,但是我不知道怎么做,后者我没写出来,谈不了改进。
总结:在这三个题目集里我更加熟悉了字符串的处理,尝试使用了正则表达式,试着运用了不用确定数组长度ArrayList数组,更加明白了类间关系聚合是怎么一回事。不过从菜单计价程序问题我很明白我根本不会用类里面的类数组与ArrayList的结合,我不会增加菜单或者订单。我也不会处理输入数据。字符串的处理应用从C语言开始就是我的心头大患。在这几个方面我还需要加强学习。对于作业这事我想提一点建议:希望老师在叫我们画类图后给出一个标准答案。不然真的会喜滋滋地以为就自己对了,其他人都错了。虽然说答案不唯一,可是老师的答案有助于我们在非常明显写错的时候改正。(和其他人讨论根本就谁也说服不了谁啊!)
标签:总结,题目,int,getValue,getYear,date,day,getMonth From: https://www.cnblogs.com/wuyuxuansitong/p/17358849.html