PTA OOP训练集4-6总结

发布时间 2023-04-30 20:16:46作者: Swery_X

 

一、前言

二、设计与分析

三、踩坑心得

四、改进建议

五、总结

 

南昌航空大学 软件学院 2201108郭海涛

一、前言

    OOP4-6次题目集,较前三次,知识点覆盖的范围更加广,难度也骤然上升,尤其是第六次题目集,从第三题开始就没有类图了,需要我们自行根据题目的需求和输入输出来设计各个类,以及类和类之间的关系。这几次的题目都比较综合,更有几题难度明显较高,如题目集4的第一题,题目集5的最后一题,和题目6的第三、四、五题。这些题目性质都比较综合,需要考虑到很多方面,尤其是类与类之间的关系,这里一定要想清楚。总的来说,就是要好好遵守七个面向对象的设计原则来设计。

二、设计与分析

   (1)第四次题目集的7-1

      这一题,对比起这一次题目集和之前所有的题目集,都是最难的一道题,这里面设计的很多类与类之间的关系,远比之前写过的题目复杂。在这里只给出我对这道题的一些设计和类图。

在题目中,程序已经给出了要设计的部分类:菜品类Dish保存每道菜的信息,即菜品名称和菜品价格,还有一个计算菜品价格的方法getprice;菜谱类Menu:保存饭店提供的所有菜的信息(即包含一个Dish型的数组),以及一个添加一道菜品信息的方法addDish和一个根据菜名在菜谱中查找菜品信息的方法searthDish;点菜记录类Record:保存订单上的一道菜品记录(包含序号和菜品、份额)还有一个计价的方法;订单类Order:保存订单上的每一条信息(即包含一个Record类的数组),还有添加一条菜品信息到订单中的方法addARecord和删除记录的方法delARecordByOrderNum和查找记录的方法findRecordByNum。

  根据题目,我们有一个具体的输入格式,因此,我们可以以行为划分,将每一行的信息都储存到一个动态数组中,待检测到输入end时,停止输入,开始处理。

  处理也要分为好几部分,每个含有table的字符串到下一个含有table的字符串就是一个部分,要将每个部分开处理,分开存储结果。

  然后就是针对每一桌(同一个table数下),计算根据每一道菜的名字、菜的份额,来计算出菜的单价,进而计算出总价。并将结果输出。

   (2)第五次题目集的7-5

      程序要求实现功能:  

        1、求下n天

        2、求前n天

        3、求两个日期相差的天数

      题目提供类图:

  

 

    我提交的源代码如下

查看代码
 import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        int start = input.nextInt();//接收第一个数字,判断执行哪一种方法
        if(start == 1){//执行求下N天
            DateUtil date_1 = new DateUtil(input.nextInt(),input.nextInt(),input.nextInt());
            //先判断是否非法
            if(!date_1.getDay().getMonth().getYear().validate()||!date_1.getDay().getMonth().validate()||!date_1.getDay().validate())
                System.out.println("Wrong Format");
            else
                System.out.println(date_1.getNextNdays(input.nextInt()).showDate());
        }
        if(start == 2){//执行求上N天
            DateUtil date_2 = new DateUtil(input.nextInt(),input.nextInt(),input.nextInt());
            //先判断是否非法
            if(!date_2.getDay().getMonth().getYear().validate()||!date_2.getDay().getMonth().validate()||!date_2.getDay().validate())
                System.out.println("Wrong Format");
            else
                System.out.println(date_2.getPriviousNDays(input.nextInt()).showDate());
        }
        if(start == 3){//判断两日期之间相隔的天数
            DateUtil date_3_1 = new DateUtil(input.nextInt(),input.nextInt(),input.nextInt());
            DateUtil date_3_2 = new DateUtil(input.nextInt(),input.nextInt(),input.nextInt());
            //判断是否非法
            if(!date_3_1.getDay().getMonth().getYear().validate()||!date_3_1.getDay().getMonth().validate()||!date_3_1.getDay().validate()||!date_3_2.getDay().getMonth().getYear().validate()||!date_3_2.getDay().getMonth().validate()||!date_3_2.getDay().validate())
                System.out.println("Wrong Format");
            else{
                if(date_3_1.compareDates(date_3_2)){//date_3_1日期更大
                    System.out.println(date_3_1.getDaysofDates(date_3_2));
                }
                else//date_3_2日期更小
                    System.out.println(date_3_2.getDaysofDates(date_3_1));
            }
        }
    }
}

class Year{
    private int year;//年
    public Year(){};//构造方法
    public Year(int year){
        this.year = year;
    }
    //getter和setter方法
    public int getValue(){
        return this.year;
    }
    public void setValue(int year){
        this.year = year;
    }
    //判断闰年
    public boolean isLeapYear(){
        if(this.year%4 == 0&&this.year%100!=0||this.year%400==0)
            return true;
        else
            return false;
    }
    //判断合法性
    public boolean validate(){
        if(this.year<1900||this.year>2050)
            return false;
        else
            return true;
    }
    //年数增加
    public void yearIncrement(){
        this.year+=1;
    }
    //年数减少
    public void yearReduction(){
        this.year-=1;
    }
}

class Month{
    private int month;//月
    private Year year = new Year();//年
    public Month(){}//构造方法
    public Month(int year,int month){
        this.year.setValue(year);
        this.month = month;
    }
    //getter和setter方法
    public int getValue(){
        return this.month;
    }
    public void setValue(int month){
        this.month = month;
    }
    public Year getYear(){
        return this.year;
    }
    public void setYear(Year year){
        this.year = year;
    }
    //复位最大和最小
    public void resetMin(){
        this.month = 1;
    }
    public void resetMax(){
        this.month = 12;
    }
    //判断合法性
    public boolean validate(){
        if(this.month<1||this.month>12)
            return false;
        else
            return true;
    }
    //月数增
    public void monthIncrement(){
        this.month+=1;
    }
    //月数减
    public void monthReduction(){
        this.month-=1;
    }
}

class Day{
    private Month month = new Month();//月
    private int day;//天
    //每一月的最大天数
    private int [] mon_maxnum = new int[] {0,31,28,31,30,31,30,31,31,30,31,30,31};
    public Day(){}//构造方法
    public Day(int year,int month,int day){
        this.getMonth().getYear().setValue(year);
        this.month.setValue(month);
        this.day = day;
    }
    //getter和setter方法
    public Month getMonth(){
        return this.month;
    }
    public void setMonth(Month month){
        this.month = month;
    }
    
    public int getValue(){
        return this.day;
    }
    public void setValue(int day){
        this.day = day;
    }
    //复位最大最小
    public void resetMin(){
        this.day = 1;
    }
    public void resetMax(){
        if(this.month.getValue()==2&&this.month.getYear().isLeapYear())
            this.day = mon_maxnum[this.month.getValue()] + 1;
        else
            this.day = mon_maxnum[this.month.getValue()];
    }
    public boolean validate(){
        if(this.day<1)//天数小于0
            return false;
        //非2月大于该月最大天数
        else if (this.month.getValue()!=2&&this.day>mon_maxnum[this.month.getValue()])
            return false;
        //2月非闰年大于28
        else if(this.month.getValue()==2&&!this.month.getYear().isLeapYear()&&this.day>mon_maxnum[this.month.getValue()])
            return false;
        //2月闰年大于29
        else if(this.month.getValue()==2&&this.month.getYear().isLeapYear()&&this.day>mon_maxnum[this.month.getValue()]+1)
            return false;
        else
            return true;
    }
    
    public void dayIncrement(){//日加一
        this.day+=1;
    }
    public void dayReduction(){//日减一
        this.day-=1;
    }
}

class DateUtil{
    private Day day = new Day();
    //构造方法
    public DateUtil(){}
    public DateUtil(int y,int m,int d){
        this.day.setValue(d);
        this.day.getMonth().setValue(m);
        this.day.getMonth().getYear().setValue(y);
    }
    //getter和setter方法
    public Day getDay(){
        return this.day;
    }
    public void setDay(Day d){
        this.day = d;
    }
    public boolean checkInputValidity(){
        if(this.day.validate())
            return true;
        else
            return false;
    }
    public boolean compareDates(DateUtil date){//true 表示当前的日期更大
        if(this.day.getMonth().getYear().getValue()>date.getDay().getMonth().getYear().getValue())
            return true;
        else if(this.day.getMonth().getYear().getValue()==date.getDay().getMonth().getYear().getValue()&&this.day.getMonth().getValue()>date.getDay().getMonth().getValue())
            return true;
        else if(this.day.getMonth().getYear()==date.getDay().getMonth().getYear()&&this.day.getMonth().getValue()==date.getDay().getMonth().getValue()&&this.day.getValue()>date.getDay().getValue())
            return true;
        else
            return false;
    }
    
    public boolean equalTwoDates(DateUtil date){
        if(this.day.getValue() == date.getDay().getValue()&&this.day.getMonth().getValue()==date.getDay().getMonth().getValue()&&this.day.getMonth().getYear().getValue()==date.getDay().getMonth().getYear().getValue())
            return true;
        else
            return false;
    }
    
    public String showDate(){
        String date = Integer.toString(this.day.getMonth().getYear().getValue())+"-"+Integer.toString(this.day.getMonth().getValue())+"-"+Integer.toString(this.day.getValue());
        return date;
    }
    
    public DateUtil getNextNdays(int n){
        for(int i = 0;i<n;i++){
            this.day.dayIncrement();
            if(!this.day.validate()){
                this.day.getMonth().monthIncrement();
                
                if(!this.day.getMonth().validate()){
                    this.day.getMonth().getYear().yearIncrement();
                    this.day.getMonth().resetMin();
                }
                this.day.resetMin();
            }
        }
        return this;
    }
    
    public DateUtil getPriviousNDays(int n){
        for(int i = 0;i<n;i++){
            this.day.dayReduction();
            if(!this.day.validate()){
                this.day.getMonth().monthReduction();
                if(!this.day.getMonth().validate()){
                    this.day.getMonth().getYear().yearReduction();
                    this.day.getMonth().resetMax();
                }
                this.day.resetMax();
            }
        }
        return this;
    }
    
    public int getDaysofDates(DateUtil date){//默认该日期更大
        int count = 0;
        if(this.equalTwoDates(date))//如果两日期相等,就返回0
            return 0;
        else
            while(!this.equalTwoDates(date)){//不相等,返回count
                this.day.dayReduction();
                count++;
                if(!this.day.validate()){//如果日非法
                    this.day.getMonth().monthReduction();//月减一
                    if(!this.day.getMonth().validate()){//如果月非法
                        this.day.getMonth().getYear().yearReduction();//年减一
                        this.day.getMonth().resetMax();//月设为最大
                    }
                    this.day.resetMax();//设置日为该月最大
                }
            }
        return count;
    }
}

    这道题由于给出了类图,不需要我们设计,所以还是十分简单的,主要就是设计三个类:year(年)、month(月)、day(日),month组合year,year组合month,形成一个一层一层的关系,然后日期类组合day。完成程序。

    我在这里注意了几点:非法检测,year类的非法检测只检测年是否非法,month类的非法检测只检测月是否小于1或者大于12,而日的非法就要结合月一起分析。在之前几次题目集中,我将所有的非法性都放在一起检测,这里做了改动,便于检查。

   (3)第五次题目集的7-6

      程序要求实现功能:  

        1、求下n天

        2、求前n天

        3、求两个日期相差的天数

      题目提供类图:

      我提交的源代码如下:

查看代码
 import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner input = new Scanner (System.in);
        int start = input.nextInt();//start用于接收第一个数据,判断下一步执行什么操作
        if(start == 1){
            DateUtil date_1 = new DateUtil(input.nextInt(),input.nextInt(),input.nextInt());
            //先判断是否非法
            if(!date_1.getYear().validate()||!date_1.getMonth().validate()||!date_1.checkInputValidity())
                System.out.print("Wrong Format");
            else{
                int n = input.nextInt();
                System.out.print(date_1.showDate()+" next "+n+" days is:"+date_1.getNextNDays(n).showDate());
            }
        }
        else if(start ==2){
            DateUtil date_2 = new DateUtil(input.nextInt(),input.nextInt(),input.nextInt());
            //先判断是否非法
            if(!date_2.getYear().validate()||!date_2.getMonth().validate()||!date_2.checkInputValidity())
                System.out.print("Wrong Format");
            else{
                int n = input.nextInt();
                System.out.print(date_2.showDate()+" previous "+n+" days is:"+date_2.getPreviousNDays(n).showDate());
            }
        }
        else if(start == 3){
            DateUtil date_3_1 = new DateUtil(input.nextInt(),input.nextInt(),input.nextInt());
            DateUtil date_3_2 = new DateUtil(input.nextInt(),input.nextInt(),input.nextInt());
            //先判断是否非法
            if(!date_3_1.getYear().validate()||!date_3_1.getMonth().validate()||!date_3_1.checkInputValidity()||!date_3_2.getYear().validate()||!date_3_2.getMonth().validate()||!date_3_2.checkInputValidity())
                System.out.print("Wrong Format");
            else{
                if(date_3_1.compareTwoDates(date_3_2)){//因为getDaysofDates方法有大小的区别,如果date_3_1大
                    System.out.print("The days between "+date_3_1.showDate()+" and "+date_3_2.showDate()+" are:"+date_3_1.getDaysofDates(date_3_2));
                }
                else
                    System.out.print("The days between "+date_3_1.showDate()+" and "+date_3_2.showDate()+" are:"+date_3_2.getDaysofDates(date_3_1));
            }
        }
        else //除了1,2,3外的其他输入都是非法输入
            System.out.print("Wrong Format");
    }
}

class Year{
    private int year;
    //构造方法
    public Year(){}
    public Year(int year){
        this.year = year;
    }
    //getter和setter方法
    public int getValue(){
        return this.year;
    }
    public void setValue(int year){
        this.year = year;
    }
    //判断闰年
    public boolean isLeapYear(){
        if(this.year%4==0&&this.year%100!=0||this.year%400==0){
            return true;
        }
        else 
            return false;
    }
    //判断输入是否非法
    public boolean validate(){
        if(this.year<1820||this.year>2020)
            return false;
        else
            return true;
    }
    //年份加减
    public void yearIncrement(){
        this.year+=1;
    }
    public void yearReduction(){
        this.year-=1;
    }
}

class Month{
    private int month;
    //构造方法
    public Month(){}
    public Month(int month){
        this.month = month;
    }
    //getter和setter方法
    public int getValue(){
        return this.month;
    }
    public void setValue(int month){
        this.month = month;
    }
    //月份复位到最大和最小
    public void resetMin(){
        this.month = 1;
    }
    public void resetMax(){
        this.month = 12;
    }
    //判断是否非法
    public boolean validate(){
        if(this.month<1||this.month>12)
            return false;
        else
            return true;
    }
    //月份加减
    public void monthIncrement(){
        this.month+=1;
    }
    public void monthReduction(){
        this.month-=1;
    }
}

class Day{
    private int day;
    //构造方法
    public Day(){}
    public Day(int day){
        this.day = day;
    }
    //getter和setter方法 
    public int getValue(){
        return this.day;
    }
    public void setValue(int day){
        this.day = day;
    }
    //日期的加减
    public void dayIncrement(){
        this.day +=1;
    }
    public void dayReduction(){
        this.day -=1;
    }
}

class DateUtil{
    private Year year = new Year();
    private Month month = new Month();
    private Day day = new Day();
    private int [] mon_maxnum = new int []{31,31,28,31,30,31,30,31,31,30,31,30,31};
    //构造方法 
    public DateUtil (){}
    public DateUtil (int y,int m,int d){
        this.year.setValue(y);
        this.month.setValue(m);
        this.day.setValue(d);
    }
    //getter和setter方法
    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.day.setValue(1);
    }
    public void setDayMax(){
        if(this.month.getValue()!=2)
            this.day.setValue(mon_maxnum[this.month.getValue()]);
        else if(this.month.getValue()==2&&!this.year.isLeapYear())
            this.day.setValue(mon_maxnum[this.month.getValue()]);
        else
            this.day.setValue(mon_maxnum[this.month.getValue()]+1);
    }
    //检查日期是否合法
    public boolean checkInputValidity(){
        if(this.day.getValue()<1||this.month.getValue()!=2&&this.day.getValue()>mon_maxnum[this.month.getValue()])//不是2月却大于该月最大
            return false;
        else if(this.month.getValue()==2&&this.year.isLeapYear()&&this.day.getValue()>mon_maxnum[this.month.getValue()]+1)
            return false;
        else if(this.month.getValue()==2&&!this.year.isLeapYear()&&this.day.getValue()>mon_maxnum[this.month.getValue()])
            return false;
        else
            return true;
    }
    //得到下N天
    public DateUtil getNextNDays(int n){
        for(int i = 0 ;i<n;i++){
            this.day.dayIncrement();
            if(!this.checkInputValidity()){
                this.month.monthIncrement();
                if(!this.month.validate()){
                    this.year.yearIncrement();
                    this.month.resetMin();

                }
                this.setDayMin();
            }
            
        }
        return this;
    }
    //得到上N天
    public DateUtil getPreviousNDays(int n){
        for(int i = 0 ;i<n;i++){//进行N次循环
            this.day.dayReduction();
            if(!this.checkInputValidity()){//日非法就减一个月
                this.month.monthReduction();
                if(!this.month.validate()){//月非法就减一年
                    this.year.yearReduction();
                    this.month.resetMax();//月变为最大
                }
                this.setDayMax();//日期变为该月最大天数
                
            }
            
        }
        return this;
    }
    //比较两个日期的大小
    public boolean compareTwoDates(DateUtil date){
        if(this.year.getValue()>date.getYear().getValue())//年大就大
            return true;
        //年相同月大就大
        else if(this.year.getValue()==date.getYear().getValue()&&this.month.getValue()>date.getMonth().getValue())
            return true;
        //月相同日大就大
        else if(this.month.getValue()==date.getMonth().getValue()&&this.day.getValue()>date.getDay().getValue())
            return true;
        else
            return false;
    }
    //判断日期是否相等
    public boolean equalTwoDates(DateUtil date){
        if(this.year.getValue()==date.getYear().getValue()&&this.month.getValue()==date.getMonth().getValue()&&this.day.getValue()==date.getDay().getValue())
            return true;
        else
            return false;
    }
    //得到两日期之间相差的天数
    public int getDaysofDates(DateUtil date){//默认该日期更大
        int count = 0;
        if(this.equalTwoDates(date))
            return 0;
        else{
            while(!this.equalTwoDates(date)){
                count+=1;
                this.day.dayReduction();
                if(!this.checkInputValidity()){//如果日非法就退一个月
                    this.month.monthReduction();
                    if(!this.month.validate()){//月非法就退一个年
                        this.year.yearReduction();//年减一
                        this.month.resetMax();//年数为最大
                    }
                    this.setDayMax();//天数为该月最大值
                }
            }
            return count;
        }
        
    }

    public String showDate(){
        String date = Integer.toString(this.year.getValue())+"-"+Integer.toString(this.month.getValue())+"-"+Integer.toString(this.day.getValue());
        return date;
    }
}

    这道题与上一道十分类似,甚至于DateUitil类中方法大体都是一样的,和上一题不同的是,这一题不再是一层一层的组合,而是一个DateUtil类组合Year类、Month类、Day类,我觉得与上一题相比,这道题在设计层面更加合理。因为year、month、day三个类之间本来就是相互独立的,本身之间应该并没有关系,而DateUtil类就是用来整合Day、Month、Year类的,所以这道题目的设计比上一道题要合理。

    至于其他方面,和上一题别无二致,方法的设计都几乎一致。

   (4)第六次题目集的7-3

    题目要求:PTA 7-3

    我所提交的源代码如下:

查看代码
 import java.util.*;
import java.time.*;


public class Main{
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        String str = "GHT";
        StringBuffer sb = new StringBuffer();
        while(true){
            
            str = input.nextLine();
            //str = str.trim();
            //如果输入了exit就退出
            if(str.equals("exit"))
                break;
            //把所有数据都存储到StingBuffer 里,每输入一次加一个换行符用于后续操作
            sb.append(str);
            sb.append("\n");
        }
        DealData dealData = new DealData(sb);
        dealData.getDealDataResult();//数据的处理
        input.close();
    }
}

class HydrologicalInfo{
    private LocalDateTime measureDateTime;//时间
    private double objectWaterLevel;//目标水位
    private double actualWaterLevel;//实际水位
    private double objectGateOpening;//目标开度
    private double actualGateOpening;//实际开度
    private double waterFlow;//流量
    public HydrologicalInfo() {
    }
    public HydrologicalInfo(LocalDateTime measureDateTime, double objectWaterLevel, double actualWaterLevel,
            double objectGateOpening, double actualGateOpening, double waterFlow) {
        this.measureDateTime = measureDateTime;
        this.objectWaterLevel = objectWaterLevel;
        this.actualWaterLevel = actualWaterLevel;
        this.objectGateOpening = objectGateOpening;
        this.actualGateOpening = actualGateOpening;
        this.waterFlow = waterFlow;
    }
    public LocalDateTime getMeasureDateTime() {
        return measureDateTime;
    }
    public double getObjectWaterLevel() {
        return objectWaterLevel;
    }
    public double getActualWaterLevel() {
        return actualWaterLevel;
    }
    public double getObjectGateOpening() {
        return objectGateOpening;
    }
    public double getActualGateOpening() {
        return actualGateOpening;
    }
    public double getWaterFlow() {
        return waterFlow;
    }
    public void setMeasureDateTime(LocalDateTime measureDateTime) {
        this.measureDateTime = measureDateTime;
    }
    public void setObjectWaterLevel(double objectWaterLevel) {
        this.objectWaterLevel = objectWaterLevel;
    }
    public void setActualWaterLevel(double actualWaterLevel) {
        this.actualWaterLevel = actualWaterLevel;
    }
    public void setObjectGateOpening(double objectGateOpening) {
        this.objectGateOpening = objectGateOpening;
    }
    public void setActualGateOpening(double actualGateOpening) {
        this.actualGateOpening = actualGateOpening;
    }
    public void setWaterFlow(double waterFlow) {
        this.waterFlow = waterFlow;
    }
}

class CheckData{
    private String data;//一条数据
    private int row;//该数据的行数
    public void setData(String data,int row){//setter方法
        this.data = data;
        this.row = row;
    }
    public String[] getData(){//getter方法
        String [] strs = data.split("\\|");//添加\\是为了转义
        return strs;
    }
    public String getDataLine(){//得到该条数据
        return  this.data;
    }
    public boolean validataData(){//合法性检测
        int n = data.length()-data.replaceAll("\\|", "").length();
        if(n!=4){
            return false;
        }
        else
            return true;
    }
    public boolean validateMeasureDateTime(String measureDateTime){//时间检测
        
        measureDateTime = measureDateTime.trim();//去除多余空格
    String [] dateTime = measureDateTime.split("\\s+");
        if(dateTime[0].matches("[1-9]\\d{0,3}/"+//年
         "((([13578]|1[02])/([1-9]|([12][0-9])|3[01]))|(([469]|11)/([1-9]|([12][0-9])|30))|((2/(([1-9])|1[0-9]|2[0-8]))))")&&
         dateTime[1].matches("([02468]|1[02468]|2[02]):00")){
            return true;
        }
        else{

            return false;
        }

    }
    public boolean validateWaterLevel(String waterLevel){//水位检测
        waterLevel = waterLevel.trim();//去除多余空格
        if(waterLevel.matches("([1-9]\\d{0,2}\\.[0-9]\\d{0,2})|([1-9]\\d{0,2})"))//可无小数,有也不能超过3位小数,且范围为1-999
            return true;
        else{
            return false;
        }
    }

    public boolean validateGateOpening(String gateOpening){//闸门检测
        gateOpening = gateOpening.trim();//去除多余空格
        if(gateOpening.matches("[1-9]\\.\\d{2}")){//一定要有2位小数保留,且范围为1-9.99
            return true;            
        }
        else{
            return false;
        }       
    }
    public boolean validateFlow(String Flow){//流量检测
        Flow = Flow.trim();//去除多余空格
        if(Flow.matches("([1-9]\\d{0,2}\\.[0-9]\\d{0,2})|([1-9]\\d{0,2})")){//1-999,可无小数,有则不能超过3位
            return true;
        }
        else
            return false;
    }
    //把String型数据转换为hydro型
    public HydrologicalInfo toHydrologicalInfo(){
        String d [] = data.split("\\|");
        String DateTime[] = d[0].trim().split("\\s+");
        String Date[] = DateTime[0].split("/");
        String Time[] = DateTime[1].split(":");
        String gateData[] = getData()[3].split("/");
        LocalDateTime date = LocalDateTime.of(Integer.parseInt(Date[0].trim()),Integer.parseInt(Date[1].trim()),Integer.parseInt(Date[2].trim()),Integer.parseInt(Time[0].trim()),Integer.parseInt(Time[1].trim()),1);
        double objWL = Double.parseDouble(this.getData()[1]);
        double actWL = Double.parseDouble(this.getData()[2]);
        double objGO = Double.parseDouble(gateData[0]);
        double actGO = Double.parseDouble(gateData[1]);
        double waterFlow = Double.parseDouble(this.getData()[4]);
        HydrologicalInfo h1 = new HydrologicalInfo(date,objWL,actWL,objGO,actGO,waterFlow);
        return h1;
    }
}



class DealData{
    private StringBuffer sb;

    public DealData() {
    }
    public DealData(StringBuffer sb) {
        this.sb = sb;
    }
    public StringBuffer getSb() {
        return sb;
    }
    public void setSb(StringBuffer sb) {
        this.sb = sb;
    }
    public void getDealDataResult(){//进行数据的处理
        boolean flag =true;//判断是否有非法的数据存在
        String str = sb.toString();//转为String类便于后续运用
        str = str.trim();//去除首尾空白符;
        if(str.equals("")){//如果没有输入
            System.out.printf("Max Actual Water Level:0.00\n");
            System.out.printf("Total Water Flow:0.00");
            System.exit(1);//退出程序
        }
        else{
        String data [] = str.split("\n");//将每一行的数据分开
        CheckData checkdata[] = new CheckData[data.length];//用于后续处理数据
        HydrologicalInfo hydro[] =  new HydrologicalInfo[data.length];//用于后续存储数据
        for(int i = 0;i<data.length;i++){
            checkdata[i] = new CheckData();
            hydro [i] = new HydrologicalInfo();
            checkdata[i].setData(data[i], i+1);//把data和row设置好
            if(!checkdata[i].validataData()){//如果输入非法
                flag = false;
                System.out.println("Wrong Format");
                System.out.println("Data:"+checkdata[i].getDataLine());
                continue;
            }
            String [] part = data[i].split("\\|");//data每一部分的数据
            String [] gateOpening = new String [2];
            if(part.length>=3){
                gateOpening = part[3].split("/");//开度的两个值
            }
            else{//防止数组过限
                gateOpening[0] = "2";
                gateOpening[1] = "1";
            }
            
            if(!checkdata[i].validateMeasureDateTime(part[0])){//如果时间非法
                System.out.println("Row:"+(i+1)+",Column:1Wrong Format");
            }
            if(!checkdata[i].validateWaterLevel(part[1])){//如果ob水位非法
                System.out.println("Row:"+(i+1)+",Column:2Wrong Format");
            }
            if(!checkdata[i].validateWaterLevel(part[2])){//如果act水位非法
                System.out.println("Row:"+(i+1)+",Column:3Wrong Format");
            }
            if(!checkdata[i].validateGateOpening(gateOpening[0])){//如果ob开度非法
                System.out.println("Row:"+(i+1)+",Column:4Wrong Format");
            }
            if(gateOpening.length==2){//数组的长度要为2
                if(!checkdata[i].validateGateOpening(gateOpening[1])){//如果act开度非法
                System.out.println("Row:"+(i+1)+",Column:5Wrong Format");
                }
            }
            else{
                System.out.println("Row:"+(i+1)+",Column:4Wrong Format");
                System.out.println("Row:"+(i+1)+",Column:5Wrong Format");
            }
            if(part.length>=5){
                if(!checkdata[i].validateFlow(part[4])){//如果流量非法
                    System.out.println("Row:"+(i+1)+",Column:6Wrong Format");
                }
            }
            else
                System.out.println("Row:"+(i+1)+",Column:6Wrong Format");
            //如果全都合法
            if(checkdata[i].validataData()&&checkdata[i].validateMeasureDateTime(part[0])&&checkdata[i].validateWaterLevel(part[1])&&checkdata[i].validateWaterLevel(part[2])&&checkdata[i].validateGateOpening(gateOpening[0])&&checkdata[i].validateGateOpening(gateOpening[1])&&checkdata[i].validateFlow(part[4])){
                //将数据存储好
                hydro[i] = checkdata[i].toHydrologicalInfo();  
            }
            else{
                //如果存在非法的情况
                flag =false;
                System.out.println("Data:"+data[i]);
            } 
        }
        if(flag){
            //所有数据全部符合法
            this.computeData(hydro);
        }
    }
        
    }
    public void computeData(HydrologicalInfo hydro[]){
        double sum = 0.00;//总流量
        double max = hydro[0].getActualWaterLevel();//水位最大值
        for(int row = 0;row<hydro.length;row++){
            if(max<hydro[row].getActualWaterLevel())
                max = hydro[row].getActualWaterLevel();
            if(hydro[row].getObjectGateOpening()<hydro[row].getActualGateOpening())//如果目标开度比实际开度更小
                System.out.println("Row:"+(row+1)+" GateOpening Warning");
        }
        for(int row = 0;row<hydro.length;row++){//得到总流量
            sum += 2*60*60*hydro[row].getWaterFlow();
        }
        System.out.printf("Max Actual Water Level:%.2f\n",max);
        System.out.printf("Total Water Flow:%.2f",sum); 
    }  
}
//1判断错误,2输出顺序错误,3、字符打错

这一道题,由于题目中给出了类图,所以类的设计方面几乎不用太多思考,只是有几个方法的方法体难以书写。

 1、正则表达式来判断日期的合法性,由于在之前的判断中关于字符串的判断都是采用equals,没有怎么用正则表达式,而且日期的合法性的判断的月还与日有关,结合在一起,所以这一部分花了很多时间。

 2、getdealresult方法,花了很多时间,因为要处理判断的先后,还有何时存储,何时输出数据,还有各种非法时所要输出的数据,所以这里花了很多时间来设计和改错。 

用POWERDESIGNER反向生成的类图如下:

    可以看出,和题目要求设计的类间关系一致。

 

   (5)第六次题目集的7-4

    题目要求:PTA 7-4

     我所提交的源代码如下:

查看代码
 import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        String str = input.nextLine();
        Deal deal = new Deal();
        while(true){
            if(str.equals("#"))//如果输入了#就退出输入
                break;
            String [] parts = str.split("\\s+");//以一个或者多个空格作为分隔
            if(parts.length!=1&&parts.length!=4){
                break;
            }
            else if(parts.length == 1){//只输入了卡号,说明为查询程序
                if(deal.checkData(parts[0]))//先检测合法性
                    deal.getMoney(parts[0]);//返回余额
            }
            else {
                //检测合法性
                if(deal.checkData(parts[0],parts[1],parts[2],Double.parseDouble(parts[3])))
                    //处理存取款
                    deal.dealMoney(parts[0],parts[1],parts[2],Double.parseDouble(parts[3]));
            }
            str = input.nextLine();
        }
        input.close();
        
    }
}

class CN_UnionPay{//银联类,用于信息的初始化,银联有多个银行
    private Bank[] banks = new Bank[2];
    public CN_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("03")};
        ATM [] atm2 = {new ATM("05"),new ATM("06")};
        banks[0] = new Bank("中国建设银行",atm1,user1);
        banks[1] = new Bank("中国工商银行",atm2,user2);
    }
    //getter和setter方法
    public Bank[] getBanks() {
        return banks;
    }
    public void setBanks(Bank[] banks) {
        this.banks = banks;
    }

    
}

class Bank{//银行类,银行有多台ATM机和多名银行账户
    private String bankName;//银行名称
    private ATM atm[];//一个银行有多个atm机
    private User user[];//一个银行有多个用户
    public Bank() {
    }
    public Bank(String bankName, ATM[] atm, User[] user) {
        this.bankName = bankName;
        this.atm = atm;
        this.user = user;
    }
    //getter和setter方法
    public String getBankName() {
        return bankName;
    }
    public void setBankName(String bankName) {
        this.bankName = bankName;
    }
    public ATM[] getAtm() {
        return atm;
    }
    public void setAtm(ATM[] atm) {
        this.atm = atm;
    }
    public User[] getUser() {
        return user;
    }
    public void setUser(User[] user) {
        this.user = user;
    }

}

class User{//用户类,一个用户有多个账户
    private String name;//用户名
    private Account[] account;//一个用户有多个账户
    public User(String name, Account[] account) {
        this.name = name;
        this.account = account;
    }
    public User() {
    }
    //getter和setter方法
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Account[] getAccount() {
        return account;
    }
    public void setAccount(Account[] account) {
        this.account = account;
    }
}

class Account{//账户类,一个账户可对应多个卡号
    private String accountNum;//账号
    private double balance;//余额
    private Card card[];//一个账户可对应多张卡
    public Account() {
    }
    public Account(String accountNum,Card[] card){//余额为固定,不需要输入
        this.accountNum = accountNum;
        this.balance = 10000;
        this.card = card;
    }
    //getter和setter方法
    public String getAccountNum() {
        return accountNum;
    }
    public void setAccountNum(String accountNum) {
        this.accountNum = accountNum;
    }
    public double getBalance() {//返回余额,很重要
        return balance;
    }
    public void setBalance(double balance) {//设置余额。很重要,用来改变账户金额
        this.balance = balance;
    }
    public Card[] getCard() {
        return card;
    }
    public void setCard(Card[] card) {
        this.card = card;
    }    
}

class Card{//银行卡类
    private String cardNum;//卡号
    private String password = "88888888";//密码   
    public Card() {
    }
    public Card(String cardNum){//密码固定,无需输入
        this.cardNum = cardNum;
    }
    //getter和setter方法
    public String getCardNum() {
        return cardNum;
    }
    public void setCardNum(String cardNum) {
        this.cardNum = cardNum;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    
}

class ATM{//ATM机类
    private String ATMNum;//ATM编号 
    public ATM(){}
    public ATM(String ATMNum){
        this.ATMNum = ATMNum;
    }
    //getter和setter方法
    public String getATMNum() {
        return ATMNum;
    }
    public void setATMNum(String aTMNum) {
        ATMNum = aTMNum;
    }
}

class Deal{//控制类,用来处理数据
    /*22201108-郭海涛
        因为CN_UnionPay类中只有banks一个属性,而card等类需要一层一层调用才能被处理,所以需要多个循环来处理*/
    private CN_UnionPay unionPay = new CN_UnionPay();
    public void dealMoney(String cardNum,String password,String atmNum,double money){//处理存取款
        for(int i = 0; i< unionPay.getBanks().length;i++){//银行
            for(int j = 0;j<unionPay.getBanks()[i].getUser().length;j++){//用户
                for(int k = 0;k<unionPay.getBanks()[i].getUser()[j].getAccount().length;k++){//账户
                    for(int L = 0; L<unionPay.getBanks()[i].getUser()[j].getAccount()[k].getCard().length;L++){//银行卡
                        if(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getCard()[L].getCardNum().equals(cardNum)){//如果输入卡号和卡号相等
                            unionPay.getBanks()[i].getUser()[j].getAccount()[k].setBalance(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()-money);//设定存取款后的余额
                            if(money<0){//如果是存款
                                System.out.printf("%s在%s的%s号ATM机上存款¥%.2f\n",unionPay.getBanks()[i].getUser()[j].getName(),unionPay.getBanks()[i].getBankName(),atmNum,Math.abs(money));
                                System.out.printf("当前余额为¥%.2f\n",unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance());
                            }
                            else{//如果是取款
                                System.out.printf("%s在%s的%s号ATM机上取款¥%.2f\n",unionPay.getBanks()[i].getUser()[j].getName(),unionPay.getBanks()[i].getBankName(),atmNum,Math.abs(money));
                                System.out.printf("当前余额为¥%.2f\n",unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance());
                            }
                        }
                    }
                }
            }
        }
    }
    public void getMoney(String cardNum){//查询余额
        for(int i = 0; i< unionPay.getBanks().length;i++){//银行
            for(int j = 0;j<unionPay.getBanks()[i].getUser().length;j++){//用户
                for(int k = 0;k<unionPay.getBanks()[i].getUser()[j].getAccount().length;k++){//账户
                    for(int L = 0; L<unionPay.getBanks()[i].getUser()[j].getAccount()[k].getCard().length;L++){//银行卡
                        if(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getCard()[L].getCardNum().equals(cardNum)){//如果输入卡号和卡号相等
                            System.out.printf("¥%.2f\n",unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance());
                        }
                    }
                }
            }
        }
    }
    public boolean checkData(String cardNum,String password,String atmNum,double money){//检验数据正确性
        boolean flagCardNum = false;
        boolean flagATM = false;
        boolean flagPassword = false;
        boolean flagMoney = false;
        boolean flagCrossBank = false;
        for(int i = 0; i< unionPay.getBanks().length;i++){//银行
            for(int j = 0;j<unionPay.getBanks()[i].getUser().length;j++){//用户
                for(int k = 0;k<unionPay.getBanks()[i].getUser()[j].getAccount().length;k++){//账户
                    for(int L = 0; L<unionPay.getBanks()[i].getUser()[j].getAccount()[k].getCard().length;L++){//银行卡
                        if(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getCard()[L].getCardNum().equals(cardNum)){
                            flagCardNum= true;
                            if(Double.parseDouble(atmNum)>=1&&Double.parseDouble(atmNum)<=6){//atm机编号在0-6之间为合法
                                flagATM = true;
                                if(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getCard()[L].getPassword().equals(password)){//如果输入密码错误
                                flagPassword = true;
                                    if(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()>money){//余额不足
                                        flagMoney = true;
                                        for(int ght = 0;ght<unionPay.getBanks()[i].getAtm().length;ght++){//
                                            if(unionPay.getBanks()[i].getAtm()[ght].getATMNum().equals(atmNum)){//如果不是跨行处理
                                                flagCrossBank = true;
                                            }
                                        }
                                    }
                                }
                            }
                            
                        }
                    }
                }
            }
        }
        if(!flagCardNum){
            System.out.println("Sorry,this card does not exist.");
            return false;
        }
        else if(!flagATM){
            System.out.println("Sorry,the ATM's id is wrong.");
            return false;
        }
        else if(!flagPassword){
            System.out.println("Sorry,your password is wrong.");
            return false;
        }
        else if(!flagMoney){
            System.out.println("Sorry,your account balance is insufficient.");
            return false;
        }
        else if(!flagCrossBank){
            System.out.println("Sorry,cross-bank withdrawal is not supported.");
            return false;
        }
        else 
            return true;
    }
    public boolean checkData(String cardNum){
        boolean flagCardNum = false;
        for(int i = 0; i< unionPay.getBanks().length;i++){//银行
            for(int j = 0;j<unionPay.getBanks()[i].getUser().length;j++){//用户
                for(int k = 0;k<unionPay.getBanks()[i].getUser()[j].getAccount().length;k++){//账户
                    for(int L = 0; L<unionPay.getBanks()[i].getUser()[j].getAccount()[k].getCard().length;L++){//银行卡
                        if(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getCard()[L].getCardNum().equals(cardNum)){//输入卡号等于卡号
                            flagCardNum= true;
                        }
                    }
                }
            }
        }
        if(flagCardNum)//如果正确
            return true;
        else
            return false;
    }
}

  这一题的设计十分巧妙,由于题目给出的很多对象都要设计实体类,尤其是银联,我一开始并不明白银联类有什么用,但是逐步想,在实验书中所给的对象都是一种递进关系:银联->银行->(ATM机)用户->账号->银行卡。联想到需要用固定的数据来判断,所以我就自然的想到了可以把初始化放在银联类中,再通过一层层调用来调用每一个数据。

  然后就简单了,实体类的设计也十分简单,构造方法、getter和setter方法、大都这样。然后就是控制类Deal,首先一定是要一个银联类作为属性,也是对数据进行初始化,接着就是对数据的处理,输入的是一行行的字符串,首先在checkdata检查非法性,再用dealmoney匹配到用户、账户、卡号、以及相应的密码,用parseInt或parseDouble 将部分输入数据转为数字余额的变动,完成处理。

  这题主要考察的就是类间关系,其他的都比较简单。

 

用POWERDISIGNER反向生成的类图如下:

   (6)第六次题目集的7-5

    题目要求:PTA 7-5

    我提交的源代码如下:

查看代码
 import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        String str = input.nextLine();
        Deal deal = new Deal();
        while(true){
            if(str.equals("#"))//检测到如果输入#号就退出
                break;
            String [] parts = str.split("\\s+");//输入的数据各部分之间可能有一个或者多个空格
            if(parts.length!=1&&parts.length!=4){//如果有1个部分或者四个部分(即查询或者存取款
                break;
            }
            else if(parts.length == 1){//查询
                if(deal.checkData(parts[0]))
                    deal.getMoney(parts[0]);
            }
            else {//存取款
                if(deal.checkData(parts[0],parts[1],parts[2],Double.parseDouble(parts[3])))
                    deal.dealMoney(parts[0],parts[1],parts[2],Double.parseDouble(parts[3]));
            }
            str = input.nextLine();
        }
        input.close();
        
    }
}

class CN_UnionPay{//银联类,用于信息的初始化,银联有多个银行
    private Bank[] banks = new Bank[3];
    public CN_UnionPay(){//信息的初始化
        Card [] card1 = {new Card("6217000010041315709","DebitAccount"),new Card("6217000010041315715","DebitAccount")};
        Card [] card2 = {new Card("6217000010041315718","DebitAccount")};
        Card [] card3 = {new Card("6217000010051320007","DebitAccount")};
        Card [] card4 = {new Card("6222081502001312389","DebitAccount")};
        Card [] card5 = {new Card("6222081502001312390","DebitAccount")};
        Card [] card6 = {new Card("62220815020013123 ","DebitAccount"),new Card("6222081502001312400","DebitAccount")};
        Card [] card7 = {new Card("6222081502051320785","DebitAccount")};
        Card [] card8 = {new Card("6222081502051320786","DebitAccount")};
        Card [] card9 = {new Card("6640000010045442002","LoanAccount"),new Card("6640000010045442003","LoanAccount")};
        Card [] card10 = {new Card("6640000010045441009","LoanAccount")};
        Card [] card11 = {new Card("6630000010033431001","LoanAccount")};
        Card [] card12 = {new Card("6630000010033431008", "LoanAccount")};
        Account [] account1 ={new Account("3217000010041315709",card1,"DebitAccount"),new Account("3217000010041315715",card2,"DebitAccount")};
        Account [] account2 ={new Account("3217000010051320007",card3,"DebitAccount")};
        Account [] account3 ={new Account("3222081502001312389",card4,"DebitAccount"),new Account("3222081502001312390",card5,"DebitAccount"),new Account("3222081502001312399",card6,"DebitAccount")};
        Account [] account4 ={new Account("3222081502051320785",card7,"DebitAccount"),new Account("3222081502051320786",card8,"DebitAccount")};
        Account [] account5 ={new Account("3640000010045442002",card9,"LoanAccount")};
        Account [] account6 ={new Account("3640000010045441009",card10,"LoanAccount")};
        Account [] account7 ={new Account("3630000010033431001",card11,"LoanAccount")};
        Account [] account8 ={new Account("3630000010033431008",card12,"LoanAccount")};
        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("中国建设银行",atm1,user1);
        banks[1] = new Bank("中国工商银行",atm2,user2);
        banks[2] = new Bank("中国农业银行",atm3,user3);
    }
    public Bank[] getBanks() {
        return banks;
    }
    public void setBanks(Bank[] banks) {
        this.banks = banks;
    }

    
}

class Bank{//银行类,银行有多台ATM机和多名银行用户
    private String bankName;
    private ATM atm[];
    private User user[];
    public Bank() {
    }
    public Bank(String bankName, ATM[] atm, User[] user) {
        this.bankName = bankName;
        this.atm = atm;
        this.user = user;
    }
    //getter和setter方法
    public String getBankName() {
        return bankName;
    }
    public void setBankName(String bankName) {
        this.bankName = bankName;
    }
    public ATM[] getAtm() {
        return atm;
    }
    public void setAtm(ATM[] atm) {
        this.atm = atm;
    }
    public User[] getUser() {
        return user;
    }
    public void setUser(User[] user) {
        this.user = user;
    }

}

class User{//用户类,一个用户有多个账户
    private String name;
    private Account[] account;
    public User(String name, Account[] account) {
        this.name = name;
        this.account = account;
    }
    public User() {
    }
    //getter和setter方法
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Account[] getAccount() {
        return account;
    }
    public void setAccount(Account[] account) {
        this.account = account;
    }
    
}

class Account{//账户类,一个账户可对应多个卡号
    private String type;
    private String accountNum;//账号
    private double balance;//余额
    private Card card[];
    public Account() {
    }
    public Account(String accountNum,Card[] card){//余额为固定,不需要输入
        this.accountNum = accountNum;
        this.balance = 10000;
        this.card = card;
    }
    public Account(String accountNum,Card[] card,String type ) {//余额为固定,不需要输入
        this.type = type;
        this.accountNum = accountNum;
        this.card = card;
        this.balance = 10000;
    }
    //getter和setter方法
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public String getAccountNum() {
        return accountNum;
    }
    public void setAccountNum(String accountNum) {
        this.accountNum = accountNum;
    }
    public double getBalance() {//返回余额,很重要
        return balance;
    }
    public void setBalance(double balance) {//设置余额。很重要,用来改变账户金额
        this.balance = balance;
    }
    public Card[] getCard() {
        return card;
    }
    public void setCard(Card[] card) {
        this.card = card;
    }    
}

class Card{//银行卡类
    private String type;//卡的类型
    private String cardNum;//卡号
    private String password = "88888888";//密码   
    public Card() {
    }
    public Card(String cardNum){//密码固定,无需输入
        this.cardNum = cardNum;
    }
    
    public Card(String cardNum,String type) {//密码固定,无需输入
        this.type = type;
        this.cardNum = cardNum;
    }
    //getter和setter方法
    public String getCardNum() {
        return cardNum;
    }
    public void setCardNum(String cardNum) {
        this.cardNum = cardNum;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    
}

class ATM{//ATM机类
    private String ATMNum;//ATM编号 
    public ATM(){}
    public ATM(String ATMNum){
        this.ATMNum = ATMNum;
    }
    //getter和setter方法
    public String getATMNum() {
        return ATMNum;
    }
    public void setATMNum(String aTMNum) {
        ATMNum = aTMNum;
    }
}

class Deal{
    private CN_UnionPay unionPay = new CN_UnionPay();
    public void dealMoney(String cardNum,String password,String atmNum,double money){//处理存取款
        String c = "c";//c用来存储处理信息的ATM机编号所对应的银行
        for(int i = 0; i< unionPay.getBanks().length;i++){//银行
            for(int j =0;j<unionPay.getBanks().length;j++){//找出atm机编号对应的银行
                for(int z =0;z<unionPay.getBanks()[j].getAtm().length;z++){
                    if(unionPay.getBanks()[j].getAtm()[z].getATMNum().equals(atmNum))//如果找到了该银行
                        c = unionPay.getBanks()[j].getBankName();
                }
            }
            for(int j = 0;j<unionPay.getBanks()[i].getUser().length;j++){//用户
                for(int k = 0;k<unionPay.getBanks()[i].getUser()[j].getAccount().length;k++){//账户
                    for(int L = 0; L<unionPay.getBanks()[i].getUser()[j].getAccount()[k].getCard().length;L++){//银行卡
                        if(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getCard()[L].getCardNum().equals(cardNum)){//如果输入卡号和卡号相等
                            boolean flag = false;//是否跨行false代表跨行了
                            for(int m =0;m<unionPay.getBanks()[i].getAtm().length;m++){
                                if(unionPay.getBanks()[i].getBankName().equals(c)){
                                    flag = true;//跨行了
                                }
                            }
                            //如果余额小于取钱金额
                            if(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()<money){
                                //前面是没有跨行,后面是余额大于0
                                if(flag&&unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()>=0)
                                    unionPay.getBanks()[i].getUser()[j].getAccount()[k].setBalance(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()-money-(money-unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance())*(0.05));
                                //没有跨行且余额大于0的其他情况
                                else if(c.equals("中国建设银行")&&unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()>=0){
                                    unionPay.getBanks()[i].getUser()[j].getAccount()[k].setBalance(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()-money*(1+0.02)-(money-unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance())*(0.05));
                                }
                                else if(c.equals("中国工商银行")&&unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()>=0){
                                    unionPay.getBanks()[i].getUser()[j].getAccount()[k].setBalance(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()-money*(1+0.03)-(money-unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance())*(0.05));
                                }
                                else if(c.equals("中国农业银行")&&unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()>=0){
                                    unionPay.getBanks()[i].getUser()[j].getAccount()[k].setBalance(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()-money*(1+0.04)-(money-unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance())*(0.05));
                                }
                                //前面是没有跨行,后面是余额小于0
                                else if(flag&&unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()<0)
                                    unionPay.getBanks()[i].getUser()[j].getAccount()[k].setBalance(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()-money-money*(0.05));
                                //没有跨行且余额小于0的其他情况
                                else if(c.equals("中国建设银行")&&unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()<0){
                                    unionPay.getBanks()[i].getUser()[j].getAccount()[k].setBalance(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()-money*(1+0.02)-money*(0.05));
                                }
                                else if(c.equals("中国工商银行")&&unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()<0){
                                    unionPay.getBanks()[i].getUser()[j].getAccount()[k].setBalance(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()-money*(1+0.03)-money*(0.05));
                                }
                                else if(c.equals("中国农业银行")&&unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()<0){
                                    unionPay.getBanks()[i].getUser()[j].getAccount()[k].setBalance(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()-money*(1+0.04)-money*(0.05));
                                }
                            }
                            //余额大于取钱金额(没有透支ght-22201108
                            else{
                                //没有跨行
                                if(flag){
                                    unionPay.getBanks()[i].getUser()[j].getAccount()[k].setBalance(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()-money);
                                }
                                //跨行了的各种情况
                                else if(c.equals("中国建设银行")){
                                    unionPay.getBanks()[i].getUser()[j].getAccount()[k].setBalance(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()-money*(1+0.02));
                                }
                                else if(c.equals("中国工商银行")){
                                    unionPay.getBanks()[i].getUser()[j].getAccount()[k].setBalance(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()-money*(1+0.03));
                                }
                                else if(c.equals("中国农业银行")){
                                    unionPay.getBanks()[i].getUser()[j].getAccount()[k].setBalance(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()-money*(1+0.04));
                                }
                            }
                            
                            //如果money小于0则为存款
                            if(money<0){
                                System.out.printf("业务:存款 %s在%s的%s号ATM机上存款¥%.2f\n",unionPay.getBanks()[i].getUser()[j].getName(),c,atmNum,Math.abs(money));
                                System.out.printf("当前余额为¥%.2f\n",unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance());
                            }
                            //money大于0则为取款
                            else{
                                System.out.printf("业务:取款 %s在%s的%s号ATM机上取款¥%.2f\n",unionPay.getBanks()[i].getUser()[j].getName(),c,atmNum,Math.abs(money));
                                System.out.printf("当前余额为¥%.2f\n",unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance());
                            }
                        }
                    }
                }
            }
            
        }
    }

    public void getMoney(String cardNum){//查询余额
        for(int i = 0; i< unionPay.getBanks().length;i++){//银行
            for(int j = 0;j<unionPay.getBanks()[i].getUser().length;j++){//用户
                for(int k = 0;k<unionPay.getBanks()[i].getUser()[j].getAccount().length;k++){//账户
                    for(int L = 0; L<unionPay.getBanks()[i].getUser()[j].getAccount()[k].getCard().length;L++){//银行卡
                        if(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getCard()[L].getCardNum().equals(cardNum)){
                            System.out.printf("业务:查询余额 ¥%.2f\n",unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance());
                        }
                    }
                }
            }
        }
    }
    public boolean checkData(String cardNum,String password,String atmNum,double money){
        boolean flagCardNum = false;//卡号
        boolean flagATM = false;//ATM编号
        boolean flagPassword = false;//银行卡密码
        boolean flagMoney = false;//取款超限
        for(int i = 0; i< unionPay.getBanks().length;i++){//银行
            for(int j = 0;j<unionPay.getBanks()[i].getUser().length;j++){//用户
                for(int k = 0;k<unionPay.getBanks()[i].getUser()[j].getAccount().length;k++){//账户
                    for(int L = 0; L<unionPay.getBanks()[i].getUser()[j].getAccount()[k].getCard().length;L++){//银行卡
                        if(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getCard()[L].getCardNum().equals(cardNum)){//判断卡号是否正确
                            flagCardNum= true;
                            if(Double.parseDouble(atmNum)>=1&&Double.parseDouble(atmNum)<=11){///判断atm机编号是否存在
                                flagATM = true;
                                if(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getCard()[L].getPassword().equals(password)){//判断密码是否正确
                                flagPassword = true;
                                    //判断借记卡是否透支,贷记卡透支是否超限
                                    if((unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()>money&&unionPay.getBanks()[i].getUser()[j].getAccount()[k].getType().equals("DebitAccount"))||
                                    (unionPay.getBanks()[i].getUser()[j].getAccount()[k].getBalance()+50000>money&&unionPay.getBanks()[i].getUser()[j].getAccount()[k].getType().equals("LoanAccount"))){
                                        flagMoney = true;
                                    }
                                }
                            }
                            
                        }
                    }
                }
            }
        }
        if(!flagCardNum){
            System.out.println("Sorry,this card does not exist.");
           // System.exit(1);
            return false;
        }
        else if(!flagATM){
            System.out.println("Sorry,the ATM's id is wrong.");
           // System.exit(1);
            return false;
        }
        else if(!flagPassword){
            System.out.println("Sorry,your password is wrong.");
           // System.exit(1);
            return false;
        }
        else if(!flagMoney){
            System.out.println("Sorry,your account balance is insufficient.");
           // System.exit(1);
            return false;
        }
        else 
            return true;
    }
    public boolean checkData(String cardNum){//checkData方法的重载
        boolean flagCardNum = false;//卡号
        for(int i = 0; i< unionPay.getBanks().length;i++){//银行
            for(int j = 0;j<unionPay.getBanks()[i].getUser().length;j++){//用户
                for(int k = 0;k<unionPay.getBanks()[i].getUser()[j].getAccount().length;k++){//账户
                    for(int L = 0; L<unionPay.getBanks()[i].getUser()[j].getAccount()[k].getCard().length;L++){//银行卡
                        if(unionPay.getBanks()[i].getUser()[j].getAccount()[k].getCard()[L].getCardNum().equals(cardNum)){//判断卡号是否正确
                            flagCardNum= true;
                        }
                    }
                }
            }
        }
        if(flagCardNum)
            return true;
        else
            return false;
    }
}

 

  这题相比于上面那题,无非就是添加了几个人、几个账户、几个卡号、然后账户类型和卡类型增加了一个透支、处理起来和上一题类似,就是Account类和Card类增加一个属性表明是信用卡还是借记卡,然后通过判断账户的类型来判断余额是否可以为负数。

  主要的难点还是透支和跨行取款,跨行取款还好,透支的算法我探索了半天,才发现真正的算法,主要就是利用该题目给出来的最后一个测试点,同一个人不断取款,从正一直到负,这个测试点能很好的检测我们的程序关于跨行取款和透支方面所存在的问题。

  对于透支,我是采用分类,如果余额大于取款金额是一种情况,如果不是是另一种情况,在这其中,还包含着跨行的判断。因为使用的是字符串来判断,因此使用了大量if else语句来判断,如果是农业银行,如果是工商银行,如果是建设银行,就是像这样的判断,用了许多,我想在后续也可以针对这一块进行改进。

 

用POWERDISIGNER反向生成的类图如下:

  

三、踩坑心得

  这次的题目难度都比较大,所以踩过的坑自然也多。下面列举一些踩过的坑,以便下次避免错误。

    (1)第五次题目集的7-6

      A)在测试用例都正确,对求两个日期之间相差的天数方法尤其是循环的条件检查过多次的条件下,提交结果中的求两个日期之间相差的天数的结果的正常日期之间却还是运行超时,使用断点调试,最后才发现是比较日期的大小中的条件有误。

错误代码:

public boolean compareTwoDates(DateUtil date){
        if(this.year.getValue()>date.getYear().getValue())
            return true;
        else if(this.year.getValue()==date.getYear().getValue())
            return true;
        else if(this.month.getValue()==date.getMonth().getValue())
            return true;
        else
            return false;
    }

正确代码:

public boolean compareTwoDates(DateUtil date){
        if(this.year.getValue()>date.getYear().getValue())
            return true;
        else if(this.year.getValue()==date.getYear().getValue()&&this.month.getValue()>date.getMonth().getValue())
            return true;
        else if(this.month.getValue()==date.getMonth().getValue()&&this.day.getValue()>date.getDay().getValue())
            return true;
        else
            return false;
    }

少了一个两个条件,导致判断错误,从而进入死循环。从这里要提醒自己,下一次编写程序要注意细节,还有多多运用断点测试这样的便于找出程序错误的工具,以便提高查找程序错误的效率。

    (2)第六次题目集的7-3

      A)在对一条数据进行处理时,运用了多次String 类中的 split方法,其中每条数据的每一部分之间以 " | " 来划分,于是我在最初分割时一直用的是 data.split("|"),虽然并没有报错,但是在整个程序写完后发现没有输出,或者是输出非常奇怪,多次检查后发现,split方法中括号中的为正则表达式,而正则表达式有一些特殊字符比如\ , | 等,这些字符直接打出来并不是字符本身,而是发挥某种作用,如果要表达该字符本身,就要在前面加\\,(第一个\表示转义,第二个\才是\,)需要这样做的特殊字符有:* . ? + ^ $ | \ / [ ] ( ) { },在使用正则表达式的时候,如果要运用这些字符要仔细注意。

      B)在对数据处理过后,应该再当一条数据的所有部分都正确的情况下,再将该条数据转为水文数据存储起来,因为再转为水文数据的过程中,是将数据分为几部分用数组存储起来,如果该条数据有部分错误,比如缺失了某一部分数据,那么数组很有可能超限。

      C)还有第一个测试点,输入为空的测试,一开始只是对存储所有数据的StringBuffer 判断是否为空,由于这种方法

    (3)第六次题目集的7-4

      A)在分析题目的时候,对于信息的初始化,动了一番脑筋,一开始想直接把初始化放在Main方法里,但是这样后续控制类进行卡号、密码等的匹配十分困 难,后续由于题目中给出的实体类的设置都是有层次的,银联包含着银行、银行包含着ATM机和多个用户、用户包含着多个账户、账户对应着多张卡。所以初始化可以放在银联中存储,确切地讲是在银联的构造方法中进行的,只要创建了银联类,就直接初始化了所有值。

      B)在进行对输入信息进行判断的过程中,关于对初始化的数据进行调用也想了很久,这个问题和初始化的数据存储在哪个位置问题比较类似,就像上一条的分析,初始化放在Main方法里不行,就是因为难以调用初始化的数据,然后不得不把处理过程放在Main方法中,耦合性很强。在修改为在银联中初始化后,就可以利用getter方法,通过银联调用银行、通过银行调用用户和ATM机,通过用户调用账户、通过账户调用卡,这样就能在处理金额和判断输入的信息时将输入的信息和初始化了的信息做匹配。

四、改进建议

  (1)第六次题目集的水文检测,由于总是出现数组超限的错误,为了避免数组超限加了很多小if语句用来避免错误(就是如果数组长度小于某个数,就不进行操作),可以把多个小if语句改为大if语句进行判断,这样可以用一个if语句来代替多个if语句的作用,精简代码,并且让程序更加具有可读性。

    (2)在很多题目集中,设计的主方法职责过重,同时负责输入、输出,有的甚至还包含着一部分的数据判断和处理,在后续的题目集,我们可以应用自己学习到的一些模式如MVC等,降低主方法的职责,让程序更加符合设计原则。

    (3)在第五次题目集的两个应用聚合关系来设计的日期程序中,对于得到两日期之间相隔的天数的方法中,单单只设计了一种情况:输入日期大于当前日期,我们可以增加一个判断,让无论是输入日期大于当前日期,还是当前日期大于输入日期,我们都能够正确的执行程序,并且得到正确的结果。

    (4)还是第六次题目集的水文检测,虽然是是依照实验书给出的类图,但是DealData类中的getDealDataResult方法中有着大量的输出,让该方法同时具有处理和输出两个作用,职责过重,我们可以重新设计该方法,或是新增一个方法,用来对每一条数据进行输出,这样还能让我们的程序逻辑更加清楚,检查起来也不会那么混乱。

五、总结

  这几次题目集的难度都比较大,十分考验我们对类的设计的能力,而且都是类与类之间的关系,在做每一道题之前,都要好好想一想类与类之间的关系是什么,应该如何调用或者如何来写类中的方法,亦或是在课中或者书中有着可以借鉴的思路,可以多加思考并且加以改造,还可以根据最近这几节课学习到的各种设计模式,用一些设计模式来设计类、和类之间的关系,而不是自己造车,写出逻辑混乱的代码。

    在这几次题目集中,我觉得最难的就是第四次题目集的第一题,菜单计价系统,我并没有写出这一题,因为这个系统要考虑的东西很多,很考验对类和方法的设计,而我目前的水平还不够,需要花费大量的时间来思考设计,如果只是硬写的话,逻辑会十分混乱,修改起来也会十分困难。为此,可以多多思考这一题和其他几题涉及到类的设计的题目,增长自己的设计水平。在很多题目中,我所提交的代码都或多或少的有一部分没有遵循设计原则,比如单一职责等等,这个例子也告诉我们,在编程之前就要好好设计类之间的关系,不能埋头就写。

    总之,这一次的题目集进一步让我们理解到了面向对象的七大设计原则,日期类的设计让我们理解了合成复用原则,ATM机让我们理解了类与类之间的调用关系,我相信只要继续像这样练习几次PTA的题目集,在未来一定能够写出非常符合面向对象的七大设计原则的程序。