南昌航空大学 软件学院 222019班 朱晓天
关于这段时间的OOP学习
这一段时间,我们也是学了很多关于java的知识。首先我们学完了面向对象程序设计的七大原则,之后我们学习了java中父类与子类的继承和多态。这一块说简单也不是很简单,说难也不是很难,继承和多态的概念还是比较好理解的,而且一些比较简单的应用还是很容易就能掌握的,但是想要灵活地运用不是一件简单的事情,我在写继承和多态的时候经常会忘记怎么写,经常要看书。
PTA作业分析
第四次训练集
7-1 菜单计价程序-3
设计点菜计价程序,根据输入的信息,计算并输出总价格。
输入内容按先后顺序包括两部分:菜单、订单,最后以"end"结束。
菜单由一条或多条菜品记录组成,每条记录一行
每条菜品记录包含:菜名、基础价格 两个信息。
订单分:桌号标识、点菜记录和删除信息、代点菜信息。每一类信息都可包含一条或多条记录,每条记录一行或多行。
桌号标识独占一行,包含两个信息:桌号、时间。
桌号以下的所有记录都是本桌的记录,直至下一个桌号标识。
点菜记录包含:序号、菜名、份额、份数。份额可选项包括:1、2、3,分别代表小、中、大份。
不同份额菜价的计算方法:小份菜的价格=菜品的基础价格。中份菜的价格=菜品的基础价格1.5。小份菜的价格=菜品的基础价格2。如果计算出现小数,按四舍五入的规则进行处理。
删除记录格式:序号 delete
标识删除对应序号的那条点菜记录。
如果序号不对,输出"delete error"
代点菜信息包含:桌号 序号 菜品名称 份额 分数
代点菜是当前桌为另外一桌点菜,信息中的桌号是另一桌的桌号,带点菜的价格计算在当前这一桌。
程序最后按输入的先后顺序依次输出每一桌的总价(注意:由于有代点菜的功能,总价不一定等于当前桌上的菜的价格之和)。
每桌的总价等于那一桌所有菜的价格之和乘以折扣。如存在小数,按四舍五入规则计算,保留整数。
折扣的计算方法(注:以下时间段均按闭区间计算):
周一至周五营业时间与折扣:晚上(17:00-20:30)8折,周一至周五中午(10:30--14:30)6折,其余时间不营业。
周末全价,营业时间:9:30-21:30
如果下单时间不在营业范围内,输出"table " + t.tableNum + " out of opening hours"
参考以下类的模板进行设计:菜品类:对应菜谱上一道菜的信息。
Dish {
String name;//菜品名称
int unit_price; //单价
int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) }
菜谱类:对应菜谱,包含饭店提供的所有菜的信息。
Menu {
Dish\[\] dishs ;//菜品数组,保存所有菜品信息
Dish searthDish(String dishName)//根据菜名在菜谱中查找菜品信息,返回Dish对象。
Dish addDish(String dishName,int unit_price)//添加一道菜品信息
}
点菜记录类:保存订单上的一道菜品记录
Record {
int orderNum;//序号\\
Dish d;//菜品\\
int portion;//份额(1/2/3代表小/中/大份)\\
int getPrice()//计价,计算本条记录的价格\\
}
订单类:保存用户点的所有菜的信息。
Order {
Record\[\] records;//保存订单上每一道的记录
int getTotalPrice()//计算订单的总价
Record addARecord(int orderNum,String dishName,int portion,int num)//添加一条菜品信息到订单中。
delARecordByOrderNum(int orderNum)//根据序号删除一条记录
findRecordByNum(int orderNum)//根据序号查找一条记录
}
### 输入格式:
桌号标识格式:table + 序号 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 时间(24小时制格式: HH/MM/SS)
菜品记录格式:
菜名+英文空格+基础价格
如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。
点菜记录格式:序号+英文空格+菜名+英文空格+份额+英文空格+份数注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。
删除记录格式:序号 +英文空格+delete
代点菜信息包含:桌号+英文空格+序号+英文空格+菜品名称+英文空格+份额+英文空格+分数
最后一条记录以“end”结束。
### 输出格式:
按输入顺序输出每一桌的订单记录处理信息,包括:
1、桌号,格式:table+英文空格+桌号+”:”
2、按顺序输出当前这一桌每条订单记录的处理信息,
每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品\*份数,序号是之前输入的订单记录的序号。如果订单中包含不能识别的菜名,则输出“\*\* does not exist”,\*\*是不能识别的菜名
如果删除记录的序号不存在,则输出“delete error”
最后按输入顺序一次输出每一桌所有菜品的总价(整数数值)格式:table+英文空格+桌号+“:”+英文空格+当前桌的总价
本次题目不考虑其他错误情况,如:桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等,在本系列的后续作业中会做要求。
输入格式:
桌号标识格式:table + 序号 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 时间(24小时制格式: HH/MM/SS)
菜品记录格式:
菜名+英文空格+基础价格
如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。
点菜记录格式:序号+英文空格+菜名+英文空格+份额+英文空格+份数注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。
删除记录格式:序号 +英文空格+delete
代点菜信息包含:桌号+英文空格+序号+英文空格+菜品名称+英文空格+份额+英文空格+分数
最后一条记录以“end”结束。
输出格式:
按输入顺序输出每一桌的订单记录处理信息,包括:
1、桌号,格式:table+英文空格+桌号+“:”
2、按顺序输出当前这一桌每条订单记录的处理信息,
每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品\*份数,序号是之前输入的订单记录的序号。如果订单中包含不能识别的菜名,则输出“\*\* does not exist”,\*\*是不能识别的菜名
如果删除记录的序号不存在,则输出“delete error”
最后按输入顺序一次输出每一桌所有菜品的总价(整数数值)格式:table+英文空格+桌号+“:”+英文空格+当前桌的总价
本次题目不考虑其他错误情况,如:桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等,在本系列的后续作业中会做要求。
分析
这一题我是在第四次训练集其他题目全部做完之后再开始做的,当时在写这道题的时候,看不太懂每个类之间属性之间的对应关系,没有想明白几个类之间的属性该进行怎样对应的处理,加上时间也不太够了,这道题就没写出来。但是之后自己仔细地想了一下,每个类之间的关系其实很清楚,Menu调用dish,Table调用Order,Order调用Records,Records再调用Dish,利用数组去进行一些数据的处理,这样来看这道题的难度其实不大,只要想通了就比较简单了。
第五次训练集
7-5 日期问题面向对象设计(聚合一)
参考题目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 //测试两个日期之间相差的天数
import java.util.*; public class Main{ public static void main(String[] args){ Scanner input = new Scanner(System.in); int choice = input.nextInt(); if(choice == 1){//测试下n天 int n = 0; int year = input.nextInt(); int month = input.nextInt(); int day = input.nextInt(); DateUtil date = new DateUtil(day,month,year); if (!date.checkInputValidity()) { System.out.println("Wrong Format"); System.exit(0); } n = input.nextInt(); if (n < 0) { System.out.println("Wrong Format"); System.exit(0); } System.out.println(date.getNextNDays(n).showDate()); } else if(choice == 2){//测试前n天 int n = 0; int year = input.nextInt(); int month = input.nextInt(); int day = input.nextInt(); DateUtil date = new DateUtil(day,month,year); if (!date.checkInputValidity()) { System.out.println("Wrong Format"); System.exit(0); } n = input.nextInt(); if (n < 0) { System.out.println("Wrong Format"); System.exit(0); } System.out.println(date.getPreviousNDays(n).showDate()); } else if(choice == 3){//测试两天之间的天数 int year1 = input.nextInt(); int month1 = input.nextInt(); int day1 = input.nextInt(); DateUtil date1 = new DateUtil(day1,month1,year1); int year2 = input.nextInt(); int month2 = input.nextInt(); int day2 = input.nextInt(); DateUtil date2 = new DateUtil(day2,month2,year2); if (date1.checkInputValidity() && date2.checkInputValidity()) { System.out.println(date1.getDaysofDates(date2)); } else { System.out.println("Wrong Format"); System.exit(0); } } else{ System.out.println("Wrong Format"); System.exit(0); } } } class DateUtil{ private Day day; private int[] mon_maxnum = {31,28,31,30,31,30,31,31,30,31,30,31}; public DateUtil(){} public DateUtil(int d,int m,int y){ this.day = new Day(y,m,d); } public Day getDay(){ return this.day; } public void setDay(Day d){ this.day = d; } /* *判断日期是否合法 */ public boolean checkInputValidity(){ if(this.getDay().getMonth().getYear().validate()&&this.getDay().getMonth().validate()&&day.validate()) return true; else return false; } public boolean comperaDates(DateUtil date){//比较两天大小 if(date.getDay().getMonth().getYear().getValue()<this.getDay().getMonth().getYear().getValue()) return true; else if(date.getDay().getMonth().getYear().getValue()==this.getDay().getMonth().getYear().getValue()&&date.getDay().getMonth().getValue()<this.getDay().getMonth().getValue()) return true; else if(date.getDay().getMonth().getYear().getValue()==this.getDay().getMonth().getYear().getValue()&&date.getDay().getMonth().getValue()==this.getDay().getMonth().getValue()&&date.getDay().getValue()<this.getDay().getValue()) return true; else return false; } public boolean equalTwoDates(DateUtil date){ if(this.getDay().getValue()==date.getDay().getValue()&&this.getDay().getMonth().getValue()==date.getDay().getMonth().getValue()&& this.getDay().getMonth().getYear().getValue()==date.getDay().getMonth().getYear().getValue()) return true; else return false; } public String showDate(){ String str = this.getDay().getMonth().getYear().getValue()+"-"+this.getDay().getMonth().getValue()+"-"+this.getDay().getValue(); return str; } public DateUtil getNextNDays(int n){ while(n!=0){ if(this.getDay().getMonth().getValue()==12&&this.getDay().getValue()==mon_maxnum[this.getDay().getMonth().getValue()-1]){//过一天跨年 this.getDay().getMonth().getYear().yearIncrement(); this.getDay().getMonth().resetMin(); this.getDay().resetMin(); n-=1; } else if(this.getDay().getMonth().getValue()==2&&this.getDay().getValue()<29&&this.getDay().getMonth().getYear().isLeapYear()==true){//闰年二月 this.getDay().dayIncrement(); n-=1; } else if(this.getDay().getMonth().getValue()==2&&this.getDay().getValue()==29&&this.getDay().getMonth().getYear().isLeapYear()==true){//跨闰年二月 this.getDay().resetMin(); this.getDay().getMonth().monthIncrement(); n-=1; } else if(this.getDay().getMonth().getValue()==2&&this.getDay().getValue()==28&&this.getDay().getMonth().getYear().isLeapYear()==false ){//跨平年二月 this.getDay().resetMin(); this.getDay().getMonth().monthIncrement(); n-=1; } else if(this.getDay().getValue()==mon_maxnum[this.getDay().getMonth().getValue() - 1]){//其他跨月 this.getDay().resetMin(); this.getDay().getMonth().monthIncrement(); n-=1; } else{//不跨月 this.getDay().dayIncrement(); n-=1; } } return this; } public DateUtil getPreviousNDays(int n){ int year1=this.getDay().getMonth().getYear().getValue(); int month1=this.getDay().getMonth().getValue(); int day1=this.getDay().getValue(); while(n!=0){ if(month1==1&&day1==1){//跨年 month1=12; year1--; day1=mon_maxnum[month1-1]; n-=1; } else if(month1==3&&day1==1&&new Year(year1).isLeapYear()==true){//减到闰年二月 month1=2; day1=29; n-=1; } else if(month1==2&&day1<=29&&day1>1&&new Year(year1).isLeapYear()==true){//闰年二月 day1--; n-=1; } else if(month1==3&&day1==1&&new Year(year1).isLeapYear()==false){//减到平年二月 month1=2; day1=28; n-=1; } else if(day1==1){//其他跨月 month1-=1; day1=mon_maxnum[month1-1]; n-=1; } else{ day1-=1; n-=1; } } DateUtil beforedate = new DateUtil(day1,month1,year1); return beforedate; } public int getDaysofDates(DateUtil date){ int days = 0; DateUtil fromDate = this; if(this.equalTwoDates(date)==true){ days=0; } /** *date1大于date2的情况下 */ else if(this.comperaDates(date)==true){ while(this.equalTwoDates(date)==false){//当两天不相等时,从大的一天开始遍历 if(fromDate.getDay().getMonth().getValue()==1&&fromDate.getDay().getValue()==1){//跨年 fromDate.getDay().getMonth().getYear().yearReduction(); fromDate.getDay().getMonth().resetMax(); fromDate.getDay().resetMax(); days+=1; } else if(fromDate.getDay().getMonth().getValue()==3&&fromDate.getDay().getValue()==1&&fromDate.getDay().getMonth().getYear().isLeapYear()==true){//闰年跨2月 fromDate.getDay().getMonth().monthReduction(); fromDate.getDay().resetMax(); days+=1; } else if(fromDate.getDay().getMonth().getValue()==2&&fromDate.getDay().getValue()<=29&&fromDate.getDay().getValue()>1&&fromDate.getDay().getMonth().getYear().isLeapYear()==true){//遍历闰年二月 fromDate.getDay().dayReduction(); days+=1; } else if(fromDate.getDay().getMonth().getValue()==2&&fromDate.getDay().getValue()<=28&&fromDate.getDay().getValue()>1&&fromDate.getDay().getMonth().getYear().isLeapYear()==false){//遍历平年二月 fromDate.getDay().dayReduction(); days+=1; } else if(fromDate.getDay().getMonth().getValue()==3&&fromDate.getDay().getValue()==1&&fromDate.getDay().getMonth().getYear().isLeapYear()==false){//跨平年二月 fromDate.getDay().getMonth().monthReduction(); fromDate.getDay().resetMax(); days+=1; } else if(fromDate.getDay().getValue()==1){//跨月 fromDate.getDay().getMonth().monthReduction(); fromDate.getDay().resetMax(); days+=1; } else{//正常遍历 fromDate.getDay().dayReduction(); days+=1; } } } /* *date1小于date2的情况下 */ else if(this.comperaDates(date)==false){ while(this.equalTwoDates(date)==false){//当两天不相等时,从大的一天开始遍历 if(date.getDay().getMonth().getValue()==1&&date.getDay().getValue()==1){//跨年 date.getDay().getMonth().getYear().yearReduction(); date.getDay().getMonth().resetMax(); date.getDay().resetMax(); days+=1; } else if(date.getDay().getMonth().getValue()==3&&date.getDay().getValue()==1&&date.getDay().getMonth().getYear().isLeapYear()==true){//闰年跨2月 date.getDay().getMonth().monthReduction(); date.getDay().resetMax(); days+=1; } else if(date.getDay().getMonth().getValue()==2&&date.getDay().getValue()<=29&&date.getDay().getValue()>1&&date.getDay().getMonth().getYear().isLeapYear()==true){//遍历闰年二月 date.getDay().dayReduction(); days+=1; } else if(date.getDay().getMonth().getValue()==2&&date.getDay().getValue()<=28&&date.getDay().getValue()>1&&date.getDay().getMonth().getYear().isLeapYear()==false){//遍历平年二月 date.getDay().dayReduction(); days+=1; } else if(date.getDay().getMonth().getValue()==3&&date.getDay().getValue()==1&&date.getDay().getMonth().getYear().isLeapYear()==false){//跨平年二月 date.getDay().getMonth().monthReduction(); date.getDay().resetMax(); days+=1; } else if(date.getDay().getValue()==1){//跨月 date.getDay().getMonth().monthReduction(); date.getDay().resetMax(); days+=1; } else{//正常遍历 date.getDay().dayReduction(); days+=1; } } } return days; } } 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.month = new Month(yearValue,monthValue); this.value = dayValue; } public int getValue(){ return this.value; } public void setValue(int value){ this.value = value; } public Month getMonth(){ return this.month; } public void setMonth(Month value){ this.month = value; } public void resetMin(){ this.value = 1; } public void resetMax(){ if(this.getMonth().getYear().isLeapYear()==true) mon_maxnum[1] = 29; else mon_maxnum[1] = 28; this.value = mon_maxnum[month.getValue() - 1];//设为当月最大值 } /* *判断天数是否合法 */ public boolean validate(){ if(this.getMonth().getYear().isLeapYear()) mon_maxnum[1] = 29;//闰年二月为29天 if(this.value>=1&&this.value<=mon_maxnum[month.getValue()-1]) return true; else return false; } public void dayIncrement(){//日期加一 this.value = this.value + 1; } public void dayReduction(){//日期减一 this.value = this.value - 1; } } class Month{ private int value; private Year year; public Month(){} public Month(int yearValue,int monthValue){ this.year = new Year(yearValue); this.value = monthValue; } public int getValue(){ return this.value; } public void setValue(int value){ this.value = value; } public Year getYear(){ return this.year; } public void setYear(Year year){ this.year = year; } public void resetMin(){ this.value = 1; } public void resetMax(){ this.value = 12; } /* *判断月份是否合法 */ public boolean validate(){ if(this.value<1||this.value>12) return false; else return true; } public void monthIncrement(){//月份加一 this.value = this.value + 1; } public void monthReduction(){//月份减一 this.value = this.value - 1; } } class Year{ private int value; public Year(){} public Year(int value){ this.value = value; } public int getValue(){ return this.value; } public void setValue(int value){ this.value = value; } public boolean isLeapYear(){ if((value%4==0&&value%100!=0)||(value%400==0)) return true; else return false; } /** *判断年分是或否合法 */ public boolean validate(){ if(value<1900||value>2050) return false; else return true; } public void yearIncrement(){//年份加一 this.value = this.value + 1; } public void yearReduction(){//年份减一 this.value = this.value - 1; } }
分析
这道题的难度就比较小了,我们之前写过日期类的处理,基本的主方法是一样的,并且这道题给出了类图,我们只需要根据类图将所有的方法补充完整就可以了,但是同时也要注意求下n天时跨闰年二月的问题,这是这道题唯一的一个易错点了。我在写判断和数据处理的方法的时候采用的是比较笨的办法,判断时将所有可能的情况全部列了出来,而在数据处理的时候,我选择了一天天遍历的方法,每过一天,n就会减一或加一,直到n等于零或者两个日期相等的时候停止,这里都是用while语句来实现的。这些方法虽然看上去笨,而且效率不高,但是这些方法都比较得稳妥,不容易漏掉某些情况,而且出错的时候也容易检查出来。
7-6 日期问题面向对象设计(聚合二)
参考题目7-3的要求,设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1820,2020] ,month∈[1,12] ,day∈[1,31] , 设计类图如下:
应用程序共测试三个功能:
- 求下n天
- 求前n天
- 求两个日期相差的天数
注意:严禁使用Java中提供的任何与日期相关的类与方法,并提交完整源码,包括主类及方法(已提供,不需修改)
import java.util.*; public class Main{ public static void main(String[] args){ Scanner input = new Scanner(System.in); int choice = input.nextInt(); if(choice == 1){//测试下n天 int n = 0; int year = input.nextInt(); int month = input.nextInt(); int day = input.nextInt(); DateUtil date = new DateUtil(year,month,day); if (!date.checkInputValidity()) { System.out.println("Wrong Format"); System.exit(0); } n = input.nextInt(); if (n < 0) { System.out.println("Wrong Format"); System.exit(0); } System.out.print(date.showDate() + " next " + n + " days is:"); System.out.println(date.getNextNDays(n).showDate()); } else if(choice == 2){//测试前n天 int n = 0; int year = input.nextInt(); int month = input.nextInt(); int day = input.nextInt(); DateUtil date = new DateUtil(year,month,day); if (!date.checkInputValidity()) { System.out.println("Wrong Format"); System.exit(0); } n = input.nextInt(); if (n < 0) { System.out.println("Wrong Format"); System.exit(0); } System.out.print(date.showDate() + " previous " + n + " days is:"); System.out.println(date.getPreviousNDays(n).showDate()); } else if(choice == 3){//测试两天之间的天数 int year1 = input.nextInt(); int month1 = input.nextInt(); int day1 = input.nextInt(); DateUtil date1 = new DateUtil(year1,month1,day1); int year2 = input.nextInt(); int month2 = input.nextInt(); int day2 = input.nextInt(); DateUtil date2 = new DateUtil(year2,month2,day2); if (date1.checkInputValidity() && date2.checkInputValidity()) { System.out.println("The days between " + date1.showDate() + " and " + date2.showDate() + " are:"+ date1.getDaysofDates(date2)); } else { System.out.println("Wrong Format"); System.exit(0); } } else{ System.out.println("Wrong Format"); System.exit(0); } } } class DateUtil{ private Year year; private Month month; private Day day; 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){ this.year = new Year(y); this.month = new Month(m); this.day = new Day(d); } public Year getYear(){ return this.year; } public void setYear(Year year){ this.year = year; } public Month getMonth(){ return this.month; } public void setMonth(Month month){ this.month = month; } public Day getDay(){ return this.day; } public void setDay(Day day){ this.day = day; } public void setDayMin(){ this.getDay().setValue(1); } public void setDayMax(){ if(this.getYear().isLeapYear()==true) mon_maxnum[1] = 29;//闰年二月29天 else mon_maxnum[1] = 28; this.getDay().setValue(mon_maxnum[this.getMonth().getValue()-1]); } /* *判断日期是否合法 */ public boolean checkInputValidity(){ if(this.getYear().isLeapYear()==true){ mon_maxnum[1] = 29; } if(this.getYear().validate()&&this.getMonth().validate()&&this.getDay().getValue()>=1&&this.getDay().getValue()<=mon_maxnum[this.getMonth().getValue()-1]) return true; else return false; } public DateUtil getNextNDays(int n){ while(n!=0){ if(this.getMonth().getValue()==12&&this.getDay().getValue()==mon_maxnum[this.getMonth().getValue()-1]){//过一天跨年 this.getYear().yearIncrement(); this.getMonth().resetMin(); this.setDayMin(); n-=1; } else if(this.getMonth().getValue()==2&&this.getDay().getValue()<29&&this.getYear().isLeapYear()==true){//闰年二月 this.getDay().dayIncrement(); n-=1; } else if(this.getMonth().getValue()==2&&this.getDay().getValue()==29&&this.getYear().isLeapYear()==true){//跨闰年二月 this.setDayMin(); this.getMonth().monthIncrement(); n-=1; } else if(this.getMonth().getValue()==2&&this.getDay().getValue()==28&&this.getYear().isLeapYear()==false ){//跨平年二月 this.setDayMin(); this.getMonth().monthIncrement(); n-=1; } else if(this.getDay().getValue()==mon_maxnum[this.getMonth().getValue() - 1]){//其他跨月 this.setDayMin(); this.getMonth().monthIncrement(); n-=1; } else{//不跨月 this.getDay().dayIncrement(); n-=1; } } return this; } public DateUtil getPreviousNDays(int n){ int year1=this.getYear().getValue(); int month1=this.getMonth().getValue(); int day1=this.getDay().getValue(); while(n!=0){ if(month1==1&&day1==1){//跨年 month1=12; year1--; day1=mon_maxnum[month1-1]; n-=1; } else if(month1==3&&day1==1&&new Year(year1).isLeapYear()==true){//减到闰年二月 month1=2; day1=29; n-=1; } else if(month1==2&&day1<=29&&day1>1&&new Year(year1).isLeapYear()==true){//闰年二月 day1--; n-=1; } else if(month1==3&&day1==1&&new Year(year1).isLeapYear()==false){//减到平年二月 month1=2; day1=28; n-=1; } else if(day1==1){//其他跨月 month1-=1; day1=mon_maxnum[month1-1]; n-=1; } else{ day1-=1; n-=1; } } DateUtil beforedate = new DateUtil(year1,month1,day1); return beforedate; } public boolean comperaDates(DateUtil date){//比较两天大小 if(date.getYear().getValue()<this.getYear().getValue()) return true; else if(date.getYear().getValue()==this.getYear().getValue()&&date.getMonth().getValue()<this.getMonth().getValue()) return true; else if(date.getYear().getValue()==this.getYear().getValue()&&date.getMonth().getValue()==this.getMonth().getValue()&&date.getDay().getValue()<this.getDay().getValue()) return true; else return false; } public boolean equalTwoDates(DateUtil date){ if(this.getDay().getValue()==date.getDay().getValue()&&this.getMonth().getValue()==date.getMonth().getValue()&& this.getYear().getValue()==date.getYear().getValue()) return true; else return false; } public int getDaysofDates(DateUtil date){ int days = 0; DateUtil fromDate = this; if(this.equalTwoDates(date)==true){ days=0; } /** *date1大于date2的情况下 */ else if(this.comperaDates(date)==true){ while(this.equalTwoDates(date)==false){//当两天不相等时,从大的一天开始遍历 if(fromDate.getMonth().getValue()==1&&fromDate.getDay().getValue()==1){//跨年 fromDate.getYear().yearReduction(); fromDate.getMonth().resetMax(); fromDate.setDayMax(); days+=1; } else if(fromDate.getMonth().getValue()==3&&fromDate.getDay().getValue()==1&&fromDate.getYear().isLeapYear()==true){//闰年跨2月 fromDate.getMonth().monthReduction(); fromDate.setDayMax(); days+=1; } else if(fromDate.getMonth().getValue()==2&&fromDate.getDay().getValue()<=29&&fromDate.getDay().getValue()>1&&fromDate.getYear().isLeapYear()==true){//遍历闰年二月 fromDate.getDay().dayReduction(); days+=1; } else if(fromDate.getMonth().getValue()==3&&fromDate.getDay().getValue()==1&&fromDate.getYear().isLeapYear()==false){//跨平年二月 fromDate.getMonth().monthReduction(); fromDate.setDayMax(); days+=1; } else if(fromDate.getDay().getValue()==1){//跨月 fromDate.getMonth().monthReduction(); fromDate.setDayMax(); days+=1; } else{//正常遍历 fromDate.getDay().dayReduction(); days+=1; } } } /* *date1小于date2的情况下 */ else if(this.comperaDates(date)==false){ while(this.equalTwoDates(date)==false){//当两天不相等时,从大的一天开始遍历 if(date.getMonth().getValue()==1&&date.getDay().getValue()==1){//跨年 date.getYear().yearReduction(); date.getMonth().resetMax(); date.setDayMax(); days+=1; } else if(date.getMonth().getValue()==3&&date.getDay().getValue()==1&&date.getYear().isLeapYear()==true){//闰年跨2月 date.getMonth().monthReduction(); date.setDayMax(); days+=1; } else if(date.getMonth().getValue()==2&&date.getDay().getValue()<=29&&date.getDay().getValue()>1&&date.getYear().isLeapYear()==true){//遍历闰年二月 date.getDay().dayReduction(); days+=1; } else if(date.getMonth().getValue()==3&&date.getDay().getValue()==1&&date.getYear().isLeapYear()==false){//跨平年二月 date.getMonth().monthReduction(); date.setDayMax(); days+=1; } else if(date.getDay().getValue()==1){//跨月 date.getMonth().monthReduction(); date.setDayMax(); days+=1; } else{//正常遍历 date.getDay().dayReduction(); days+=1; } } } return days; } public String showDate(){ String str = this.getYear().getValue()+"-"+this.getMonth().getValue()+"-"+this.getDay().getValue(); return str; } } class Day{ private int value; public Day(){} public Day(int value){; this.value = value; } public int getValue(){ return this.value; } public void setValue(int value){ this.value = value; } public void dayIncrement(){//日期加一 this.value = this.value + 1; } public void dayReduction(){//日期减一 this.value = this.value - 1; } } class Month{ private int value; public Month(){} public Month(int value){ this.value = value; } public int getValue(){ return this.value; } public void setValue(int value){ this.value = value; } public void resetMin(){ this.value = 1; } public void resetMax(){ this.value = 12; } public boolean validate(){//判断月份是否合法 if(this.value<1||this.value>12) return false; else return true; } public void monthIncrement(){//月份加一 this.value = this.value + 1; } public void monthReduction(){//月份减一 this.value = this.value - 1; } } class Year{ private int value; public Year(){} public Year(int value){ this.value = value; } public int getValue(){ return this.value; } public void setValue(int value){ this.value = value; } public boolean isLeapYear(){ if((value%4==0&&value%100!=0)||(value%400==0)) return true; else return false; } public boolean validate(){//判断年分是或否合法 if(value<1820||value>2020) return false; else return true; } public void yearIncrement(){//年份加一 this.value = this.value + 1; } public void yearReduction(){//年份减一 this.value = this.value - 1; } }
分析
这道题就是前面一题的变式,与前一题不同的是,前面一题里年月日每个类是逐级调用,而在这一题中,则是增加了一个中介类分别调用年月日三个类,使得年月日三个类之间不存在关系了,符合了迪米特法则。而这一题同样也给出了类图,只要弄清逻辑关系,将所有的方法补充完整这道题就解决了。代码中的主要方法与前一题差不多,就不过多赘述了。
第六次训练集
从这一次训练集开始,我们就开始了继承与多态的应用。
7-4 ATM机类结构设计(一)
设计ATM仿真系统,具体要求参见作业说明。
OO作业8-1题目说明.pdf
输入格式:
每一行输入一次业务操作,可以输入多行,最终以字符#终止。具体每种业务操作输入格式如下:
- 存款、取款功能输入数据格式:
卡号 密码 ATM机编号 金额
(由一个或多个空格分隔),
其中,当金额大于0时,代表取款,否则代表存款。 - 查询余额功能输入数据格式:
卡号
输出格式:
①输入错误处理
- 如果输入卡号不存在,则输出
Sorry,this card does not exist.
。 - 如果输入ATM机编号不存在,则输出
Sorry,the ATM's id is wrong.
。 - 如果输入银行卡密码错误,则输出
Sorry,your password is wrong.
。 - 如果输入取款金额大于账户余额,则输出
Sorry,your account balance is insufficient.
。 - 如果检测为跨行存取款,则输出
Sorry,cross-bank withdrawal is not supported.
。
②取款业务输出
输出共两行,格式分别为:
[用户姓名]在[银行名称]的[ATM编号]上取款¥[金额]
当前余额为¥[金额]
其中,[]说明括起来的部分为输出属性或变量,金额均保留两位小数。
③存款业务输出
输出共两行,格式分别为:
[用户姓名]在[银行名称]的[ATM编号]上存款¥[金额]
当前余额为¥[金额]
其中,[]说明括起来的部分为输出属性或变量,金额均保留两位小数。
④查询余额业务输出
¥[金额]
金额保留两位小数。
import java.util.*; public class Main{ public static void main(String[] args){ Scanner input = new Scanner(System.in); String str = input.nextLine(); while(!str.equals("#")){ String[] data = str.split("\\s+");//按单个或多个空格分割 if(data.length==1) { Action action = new Action(); action.checkMoney(data[0]); }else { ATM atm = new ATM(); atm = atm.getATM(data[2]); if(atm == null) { System.out.println("Sorry,the ATM's id is wrong."); }else { Action action = new Action(); action.changeMoney(data[0],data[1],Double.parseDouble(data[3]),data[2]); } } str = input.nextLine(); } } } class Card{ protected String cardNumber;//卡号 protected String password = "88888888";//密码 public Card(){} /* * 不更改密码设定卡号 */ public Card(String cardNumber){ this.cardNumber = cardNumber; } /* * 更改密码设定卡号 */ public Card(String cardNumber,String password){ this.cardNumber = cardNumber; this.password = password; } } class Account{ protected String accountNumber;//账户号 protected Card[] cards;//账户多张卡 protected double money=10000.00;//账户余额 public Account(){} public Account(String accountNumber,Card[] cards){ this.accountNumber = accountNumber; this.cards = cards; } } class User{ protected String name;//用户名 protected Account[] accounts;//一个用户多个用户名 public User(){} public User(Account[] accounts,String name){ this.name = name; this.accounts = accounts; } public String getName(){ return this.name; } public void setName(String name){ this.name = name; } public Account[] getAccounts(){ return this.accounts; } public void setAccounts(Account[] accounts){ this.accounts = accounts; } } class ATM{ protected String bankName;//银行名字 protected String ATMNumber;//ATM机编号 public ATM() {} public ATM(String ATMNumber) { super(); this.ATMNumber = ATMNumber; if(ATMNumber.equals("01")||ATMNumber.equals("02")||ATMNumber.equals("03")||ATMNumber.equals("04")) { this.bankName = "中国建设银行"; }else { this.bankName = "中国工商银行"; } } public ATM getATM(String nubmer) { UnionPay unionPay = UnionPay.getUnionPay(); for(Bank bank:unionPay.banks) { for(ATM atm:bank.atms) { if(nubmer.equals(atm.ATMNumber)) { return atm; } } } return null; } } class Bank{ protected String bankName; protected User[] users; protected ATM[] atms; public Bank(){} public Bank(String bankName,User[] users,ATM[] atms){ this.bankName = bankName; this.users = users; this.atms = atms; } } class UnionPay{ public static UnionPay unionPay = null;//先设置一个静态的空对象 protected Bank[] banks = new Bank[2]; /* * 储存信息 */ private UnionPay(){ Card[] card1 = {new Card("6217000010041315709"),new Card("6217000010041315715")}; Card[] card2 = {new Card("6217000010041315718")}; Card[] card3 = {new Card("6217000010051320007")}; Card[] card4 = {new Card("6222081502001312389")}; Card[] card5 = {new Card("6222081502001312390")}; Card[] card6 = {new Card("6222081502001312399"),new Card("6222081502001312400")}; Card[] card7 = {new Card("6222081502051320785")}; Card[] card8 = {new Card("6222081502051320786")}; Account[] account1 = {new Account("3217000010041315709",card1),new Account("3217000010041315715",card2)}; Account[] account2 = {new Account("3217000010051320007",card3)}; Account[] account3 = {new Account("3222081502001312389",card4),new Account("3222081502001312390",card5),new Account("3222081502001312399",card6)}; Account[] account4 = {new Account("3222081502051320785",card7),new Account("3222081502051320786",card8)}; User[] user1 = {new User(account1,"杨过"),new User(account2,"郭靖")}; User[] user2 = {new User(account3,"张无忌"),new User(account4,"韦小宝")}; ATM[] atm1 = {new ATM("01"),new ATM("02"),new ATM("03"),new ATM("04")}; ATM[] atm2 = {new ATM("05"),new ATM("06")}; banks[0] = new Bank("中国建设银行",user1,atm1); banks[1] = new Bank("中国工商银行",user2,atm2); } /* * 主要是作用于计算余额,如果不设置静态并且判断不是空返回原先的数据,余额回变回10000.00 */ public static UnionPay getUnionPay(){ if(unionPay!=null) {//当静态对象不是空的时候,返回原本的对象数据 return unionPay; } unionPay = new UnionPay(); return unionPay;//对象为空时,返回初始状态的对象 } } class Action{ protected UnionPay union = UnionPay.getUnionPay(); protected String userName = ""; protected String bankName = ""; protected Account account = null; protected Card card = null; public void changeMoney(String cardNumber,String password,double money,String atmNumber) { UnionPay union = UnionPay.getUnionPay(); String userName = ""; String bankName = ""; Account account = null; Card card = null; ATM atm = new ATM(atmNumber);//通过ATM编号确定银行 /* * 从银行到用户到账户到银行卡按照数组层层遍历 */ for(Bank bank:union.banks) { bankName = bank.bankName; for(User user:bank.users) { userName = user.name; for(Account accounts:user.accounts) { account = accounts; for(Card cardUse:account.cards) { if(cardUse.cardNumber.equals(cardNumber)) { if(cardUse.cardNumber.equals(cardNumber)) { card = cardUse; break; } } } if(card!=null) { break; } } if(card!=null) { break; } } if(card!=null) { break; } } if(card == null) { System.out.println("Sorry,this card does not exist."); return; } if(!card.password.equals(password)) { System.out.println("Sorry,your password is wrong."); return; } if(!atm.bankName.equals(bankName)) { System.out.println("Sorry,cross-bank withdrawal is not supported."); return; } if(money<=0) { account.money -= money; System.out.print(userName+"在"+bankName+"的"+atm.ATMNumber+"号ATM机上存款¥"); System.out.printf("%.2f\n", Math.abs(money)); }else { if(account.money<money) { System.out.println("Sorry,your account balance is insufficient."); return; }else { account.money -= money; System.out.print(userName+"在"+bankName+"的"+atm.ATMNumber+"号ATM机上取款¥"); System.out.printf("%.2f\n", Math.abs(money)); } } System.out.print("当前余额为¥"); System.out.printf("%.2f\n", account.money); } /* * 检查金额是否合法 */ public void checkMoney(String cardNumber) { UnionPay union = UnionPay.getUnionPay(); String userName = ""; String bankName = ""; Account account = null; Card card = null; /* * 从银行到用户到账户到银行卡按照数组层层遍历 */ for(Bank bank:union.banks) { bankName = bank.bankName; for(User user:bank.users) { userName = user.name; for(Account accounts:user.accounts) { account = accounts; for(Card cardUse:account.cards) { if(cardUse.cardNumber.equals(cardNumber)) { if(cardUse.cardNumber.equals(cardNumber)) { card = cardUse; break; } } } if(card!=null) { break; } } if(card!=null) { break; } } if(card!=null) { break; } } if(card == null) { System.out.println("Sorry,this card does not exist."); return; } System.out.print("¥"); System.out.printf("%.2f\n", account.money); } }
分析
从这一题开始,我们就不能在题目里看见完整的类图了,就需要我们开始自己做设计了,我写的代码类图如下:
根据提示,我一共写了六个实体类,其中,UnionPay类会储存用户的各类信息,一边进行判断和更改,总体上,在实现信息读取和操作的时候,我选择了创造UnionPay对象并且用数组来实现不同的用户,不同账号,不同卡之间数据的读取与处理。在读取的时候我选择了用for(:)的语句来进行遍历,用这种方法可以保证所有信息全部读取到,并且逻辑性非常强,哪个地方出现错误可以很快地找出来。
踩坑心得
在写这道题的时候一开始有一个一直没办法解决的问题,那就是同一个用户的同一张卡,没办法进行连续的处理,每次进行处理的时候,卡内的信息就会被重新定义,存款会变回初始的存款。这个问题我一直想了很久,一直没有想到解决的方法,后来上网上查了一下,这里需要把定义的对象设置为静态,实现延迟加载,而最近,我们学了单例模式,我才知道这种方法是单例模式中的一种,叫做懒汉式单例。
7-5 ATM机类结构设计(二)
设计ATM仿真系统,具体要求参见作业说明。
OO作业9-1题目说明.pdf
输入格式:
每一行输入一次业务操作,可以输入多行,最终以字符#终止。具体每种业务操作输入格式如下:
- 取款功能输入数据格式:
卡号 密码 ATM机编号 金额
(由一个或多个空格分隔) - 查询余额功能输入数据格式:
卡号
输出格式:
①输入错误处理
- 如果输入卡号不存在,则输出
Sorry,this card does not exist.
。 - 如果输入ATM机编号不存在,则输出
Sorry,the ATM's id is wrong.
。 - 如果输入银行卡密码错误,则输出
Sorry,your password is wrong.
。 - 如果输入取款金额大于账户余额,则输出
Sorry,your account balance is insufficient.
。
②取款业务输出
输出共两行,格式分别为:
业务:取款 [用户姓名]在[银行名称]的[ATM编号]上取款¥[金额]
当前余额为¥[金额]
其中,[]说明括起来的部分为输出属性或变量,金额均保留两位小数。
③查询余额业务输出
业务:查询余额 ¥[金额]
金额保留两位小数。
import java.util.*; public class Main{ public static void main(String[] args){ Scanner input = new Scanner(System.in); String str = input.nextLine(); Action action = new Action(); while(!str.equals("#")){ String[] data = str.split("\\s+");//按单个或多个空格分割 if(data.length==1) { action.searchMoney(data[0]); }else { ATM atm = new ATM(); atm = atm.getATM(data[2]); if(atm == null) { System.out.println("Sorry,the ATM's id is wrong."); }else { action.changeMoney(data[0],data[1],Double.parseDouble(data[3]),data[2]); } } str = input.nextLine(); } } } class Card{ protected String cardNumber;//卡号 protected String password = "88888888";//密码 public Card(){} /* * 不更改密码设定卡号 */ public Card(String cardNumber){ this.cardNumber = cardNumber; } /* * 更改密码设定卡号 */ public Card(String cardNumber,String password){ this.cardNumber = cardNumber; this.password = password; } } class Account{ protected String accountNumber;//账户号 protected Card[] cards;//账户多张卡 protected double money=10000.00;//账户余额 public Account(){} public Account(String accountNumber,Card[] cards){ this.accountNumber = accountNumber; this.cards = cards; } } class User{ protected String name;//用户名 protected Account[] accounts;//一个用户多个用户名 public User(){} public User(Account[] accounts,String name){ this.name = name; this.accounts = accounts; } public String getName(){ return this.name; } public void setName(String name){ this.name = name; } public Account[] getAccounts(){ return this.accounts; } public void setAccounts(Account[] accounts){ this.accounts = accounts; } } class ATM{ protected String bankName;//银行名字 protected String ATMNumber;//ATM机编号 public ATM() {} public ATM(String ATMNumber) { super(); this.ATMNumber = ATMNumber; if(ATMNumber.equals("01")||ATMNumber.equals("02")||ATMNumber.equals("03")||ATMNumber.equals("04")) { this.bankName = "中国建设银行"; }else if(ATMNumber.equals("07")||ATMNumber.equals("08")||ATMNumber.equals("09")||ATMNumber.equals("10")||ATMNumber.equals("11")){ this.bankName = "中国农业银行"; } else { this.bankName = "中国工商银行"; } } public ATM getATM(String nubmer) { UnionPay unionPay = UnionPay.getUnionPay(); for(Bank bank:unionPay.banks) { for(ATM atm:bank.atms) { if(nubmer.equals(atm.ATMNumber)) { return atm; } } } return null; } } class Bank{ protected String bankName; protected User[] users; protected ATM[] atms; public Bank(){} public Bank(String bankName,User[] users,ATM[] atms){ this.bankName = bankName; this.users = users; this.atms = atms; } } class UnionPay{ public static UnionPay unionPay = null;//先设置一个静态的空对象 protected Bank[] banks = new Bank[3]; /* * 储存信息 */ private UnionPay(){ Card[] card1 = {new Card("6217000010041315709"),new Card("6217000010041315715")}; Card[] card2 = {new Card("6217000010041315718")}; Card[] card3 = {new Card("6217000010051320007")}; Card[] card4 = {new Card("6222081502001312389")}; Card[] card5 = {new Card("6222081502001312390")}; Card[] card6 = {new Card("6222081502001312399"),new Card("6222081502001312400")}; Card[] card7 = {new Card("6222081502051320785")}; Card[] card8 = {new Card("6222081502051320786")}; Card[] card9 = {new Card("6640000010045442002"),new Card("6640000010045442003")}; Card[] card10 = {new Card("6640000010045441009")}; Card[] card11 = {new Card("6630000010033431001")}; Card[] card12 = {new Card("6630000010033431008")}; Account[] account1 = {new Account("3217000010041315709",card1),new Account("3217000010041315715",card2)}; Account[] account2 = {new Account("3217000010051320007",card3)}; Account[] account3 = {new Account("3222081502001312389",card4),new Account("3222081502001312390",card5),new Account("3222081502001312399",card6)}; Account[] account4 = {new Account("3222081502051320785",card7),new Account("3222081502051320786",card8)}; Account[] account5 = {new Account("3640000010045442002",card9)}; Account[] account6 = {new Account("3640000010045441009", card10)}; Account[] account7 = {new Account("3630000010033431001",card11)}; Account[] account8 = {new Account("3630000010033431008",card12)}; User[] user1 = {new User(account1,"杨过"),new User(account2,"郭靖"),new User(account5,"张三丰")}; User[] user2 = {new User(account3,"张无忌"),new User(account4,"韦小宝"),new User(account6, "令狐冲")}; User[] user3 = {new User(account7,"乔峰"),new User(account8, "洪七公")}; ATM[] atm1 = {new ATM("01"),new ATM("02"),new ATM("03"),new ATM("04")}; ATM[] atm2 = {new ATM("05"),new ATM("06")}; ATM[] atm3 = {new ATM("07"),new ATM("08"),new ATM("09"),new ATM("10"),new ATM("11")}; banks[0] = new Bank("中国建设银行",user1,atm1); banks[1] = new Bank("中国工商银行",user2,atm2); banks[2] = new Bank("中国农业银行",user3,atm3); } /* * 主要是作用于计算余额,如果不设置静态并且判断不是空返回原先的数据,余额回变回10000.00 */ public static UnionPay getUnionPay(){ if(unionPay!=null) {//当静态对象不是空的时候,返回原本的对象数据 return unionPay; } unionPay = new UnionPay(); return unionPay;//对象为空时,返回初始状态的对象 } } class Action{ protected UnionPay union = UnionPay.getUnionPay(); protected String userName = ""; protected String bankName = ""; protected Account account = null; protected Card card = null; public void changeMoney(String cardNumber,String password,double money,String atmNumber) { UnionPay union = UnionPay.getUnionPay(); String userName = ""; String bankName = ""; Account account = null; Card card = null; ATM atm = new ATM(atmNumber);//通过ATM编号确定银行 boolean flag = false;//判断是否可以透支 /* * 从银行到用户到账户到银行卡按照数组层层遍历 */ for(Bank bank:union.banks) { bankName = bank.bankName; for(User user:bank.users) { userName = user.name; for(Account accounts:user.accounts) { account = accounts; for(Card cardUse:account.cards) { if(cardUse.cardNumber.equals(cardNumber)) { if(cardUse.cardNumber.equals(cardNumber)) { card = cardUse; break; } } } if(card!=null) { break; } } if(card!=null) { break; } } if(card!=null) { break; } } if(card == null) { System.out.println("Sorry,this card does not exist."); return; } if(!card.password.equals(password)) { System.out.println("Sorry,your password is wrong."); return; } if(cardNumber.equals("6640000010045442002")||cardNumber.equals("6640000010045442003")||cardNumber.equals("6640000010045441009")||cardNumber.equals("6630000010033431001")||cardNumber.equals("6630000010033431008")){ flag = true; } else{ flag = false; } if(flag){ if(!atm.bankName.equals(bankName)) { if(money>0){ if(atmNumber.equals("01")||atmNumber.equals("02")||atmNumber.equals("03")||atmNumber.equals("04")){ if(account.money<0){ account.money -= money*1.07; } else{ if(account.money-money<0){ account.money -= (money-account.money)*0.05; account.money -= money*1.02; } else{ account.money -= money*1.02; } } if(account.money<-50000.00){ System.out.println("Sorry,your account balance is insufficient."); return; } System.out.print("业务:取款 "+userName+"在"+atm.bankName+"的"+atm.ATMNumber+"号ATM机上取款¥"); System.out.printf("%.2f\n", Math.abs(money)); } else if(atmNumber.equals("05")||atmNumber.equals("06")){ if(account.money<0){ account.money -= money*1.08; } else{ if(account.money-money<0){ account.money -= (money-account.money)*0.05; account.money -= money*1.03; } else{ account.money -= money*1.03; } } if(account.money<-50000.00){ System.out.println("Sorry,your account balance is insufficient."); return; } System.out.print("业务: 取款 "+userName+"在"+atm.bankName+"的"+atm.ATMNumber+"号ATM机上取款¥"); System.out.printf("%.2f\n", Math.abs(money)); } else if(atmNumber.equals("07")||atmNumber.equals("08")||atmNumber.equals("09")||atmNumber.equals("10")||atmNumber.equals("11")){ if(account.money<0){ account.money -= money*1.09; } else{ if(account.money-money<0){ account.money -= (money-account.money)*0.05; account.money -= money*1.04; } else{ account.money -= money*1.04; } } if(account.money<-50000.00){ System.out.println("Sorry,your account balance is insufficient."); return; } System.out.print("业务:取款 "+userName+"在"+atm.bankName+"的"+atm.ATMNumber+"号ATM机上取款¥"); System.out.printf("%.2f\n", Math.abs(money)); } } } else if(money<=0) { account.money -= money; if(account.money<0){ account.money -= money*0.05; } System.out.print("业务:存款 "+userName+"在"+atm.bankName+"的"+atm.ATMNumber+"号ATM机上存款¥"); System.out.printf("%.2f\n", Math.abs(money)); } else { if(account.money<0){ account.money -= money*1.05; } else{ account.money -= money; if(account.money<0){ account.money -= (money-account.money)*0.05; } } System.out.print("业务:取款 "+userName+"在"+atm.bankName+"的"+atm.ATMNumber+"号ATM机上取款¥"); System.out.printf("%.2f\n", Math.abs(money)); } } else if(flag==false){ if(!atm.bankName.equals(bankName)) { if(money>0){ if(atmNumber.equals("01")||atmNumber.equals("02")||atmNumber.equals("03")||atmNumber.equals("04")){ account.money -= money*1.02; if(account.money<0){ System.out.println("Sorry,your account balance is insufficient."); return; } System.out.print("业务:取款 "+userName+"在"+atm.bankName+"的"+atm.ATMNumber+"号ATM机上取款¥"); System.out.printf("%.2f\n", Math.abs(money)); } else if(atmNumber.equals("05")||atmNumber.equals("06")){ account.money -= money*1.03; if(account.money<0){ System.out.println("Sorry,your account balance is insufficient."); return; } System.out.print("业务:取款 "+userName+"在"+atm.bankName+"的"+atm.ATMNumber+"号ATM机上取款¥"); System.out.printf("%.2f\n", Math.abs(money)); } else if(atmNumber.equals("07")||atmNumber.equals("08")||atmNumber.equals("09")||atmNumber.equals("10")||atmNumber.equals("11")){ account.money -= money*1.04; if(account.money<0){ System.out.println("Sorry,your account balance is insufficient."); return; } System.out.print("业务:取款 "+userName+"在"+atm.bankName+"的"+atm.ATMNumber+"号ATM机上取款¥"); System.out.printf("%.2f\n", Math.abs(money)); } } } else if(money<=0) { account.money -= money; System.out.print("业务:存款 "+userName+"在"+atm.bankName+"的"+atm.ATMNumber+"号ATM机上存款¥"); System.out.printf("%.2f\n", Math.abs(money)); }else { if(account.money<money) { System.out.println("Sorry,your account balance is insufficient."); return; }else { account.money -= money; System.out.print("业务:取款 "+userName+"在"+atm.bankName+"的"+atm.ATMNumber+"号ATM机上取款¥"); System.out.printf("%.2f\n", Math.abs(money)); } } } System.out.print("当前余额为¥"); System.out.printf("%.2f\n", account.money); } /* * 检查金额是否合法 */ public void checkMoney(String cardNumber) { UnionPay union = UnionPay.getUnionPay(); String userName = ""; String bankName = ""; Account account = null; Card card = null; /* * 从银行到用户到账户到银行卡按照数组层层遍历 */ for(Bank bank:union.banks) { bankName = bank.bankName; for(User user:bank.users) { userName = user.name; for(Account accounts:user.accounts) { account = accounts; for(Card cardUse:account.cards) { if(cardUse.cardNumber.equals(cardNumber)) { if(cardUse.cardNumber.equals(cardNumber)) { card = cardUse; break; } } } if(card!=null) { break; } } if(card!=null) { break; } } if(card!=null) { break; } } if(card == null) { System.out.println("Sorry,this card does not exist."); return; } System.out.print("¥"); System.out.printf("%.2f\n", account.money); } public void searchMoney(String cardNumber){ UnionPay union = UnionPay.getUnionPay(); String userName = ""; String bankName = ""; Account account = null; Card card = null; for(Bank bank:union.banks) { bankName = bank.bankName; for(User user:bank.users) { userName = user.name; for(Account accounts:user.accounts) { account = accounts; for(Card cardUse:account.cards) { if(cardUse.cardNumber.equals(cardNumber)) { if(cardUse.cardNumber.equals(cardNumber)) { card = cardUse; break; } } } if(card!=null) { break; } } if(card!=null) { break; } } if(card!=null) { break; } } System.out.print("业务:查询余额 ¥"); System.out.printf("%.2f\n",account.money); } }
分析
这一道题目式前面一题的拓展,我写的代码类图如下:
这道题比起前面一道就是多了几个功能,首先我们要判断使用的卡是否可以透支,如果可以透支,还要判断处理过后透支金额有没有超过五万,同时我们还要计算透支的情况下所需要的手续费,其次,我们还需要多加入一个中国农业银行的初始信息。只要将这些多出来的功能加上去之后,稍微改一下前一题的代码,这道题就解决了。
踩坑心得
这题写完之后我进行提交,但是大部分的测试点就是过不了,一开始也是一直没找到原因,之后在测试用例的时候发现了问题,在输出的时候怎么也出现不了中国农业银行,这才发现原来是在ATM类中判断ATM是哪个银行的时候忘记加入中国农业银行了。
总结
这段时间的PTA作业做下来,我给自己的总结就是三个字——不熟练,在看到类图的或者各个类的属性后,很难快速地联想到各个类之间的关系,并且在没有类图自己做设计的时候,需要想好久才能想出来大体的框架该怎么弄,之后每个类之中的方法的细节该怎么写,该怎么解决遇到的问题也都要想好久。就像这三次的PTA作业的难度其实并不是很大,但是我还是需要花很多时间去想这个代码该怎么写,并且在遇到答案出现错误的时候我需要花很多时间去找到错误,会浪费很多做题的时间,对自己的代码的敏感度都不是很高。所以平时程序设计还是得多听多练,只有熟悉了设计才能写好代码。