PTA OOP第二次总结作业

发布时间 2023-04-30 21:38:25作者: 通召我的左拳

南昌航空大学 软件学院 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] , 设计类图如下:

类图.jpg

应用程序共测试三个功能:

  1. 求下n天
  2. 求前n天
  3. 求两个日期相差的天数

注意:严禁使用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] , 设计类图如下:

类图.jpg

应用程序共测试三个功能:

  1. 求下n天
  2. 求前n天
  3. 求两个日期相差的天数

注意:严禁使用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作业的难度其实并不是很大,但是我还是需要花很多时间去想这个代码该怎么写,并且在遇到答案出现错误的时候我需要花很多时间去找到错误,会浪费很多做题的时间,对自己的代码的敏感度都不是很高。所以平时程序设计还是得多听多练,只有熟悉了设计才能写好代码。