zl程序教程

您现在的位置是:首页 >  其它

当前栏目

银行与账单

银行 账单
2023-09-14 09:05:15 时间

实验题目

请添加图片描述
请添加图片描述

项目分析

1.搭建项目框架

请添加图片描述
请添加图片描述

首先结合实验描述和第一点的编码要求,搭建框架。

分析可知,首先需要搭建的是Record类,然后确定其中的成员变量的属性,结合图表可知,时间最好是作为一个单独的类Time存在,然后金额以double或者int类型存在,说明以String类型存在,然后就搭建好了,Record类与Time类的框架。

class Time{
    // 最好成员设置为私有 然后设置对应的get set方法这样更符合面相对象的封装思想
    public int month; // 月
    public int day; // 日

    // 无参数构造方法 写无参构造方法的目的是为了更好的调用 这个类的功能方法
    public Time(){}

    // 有参构造方法
    public Time(int month, int day){
        this.month = month;
        this.day = day;
    }
}

// 使用类Record存储账单记录信息,包括:时间、交易说明和⾦额
class Record{
    // 最好成员设置为私有 然后设置对应的get set方法这样更符合面相对象的封装思想

    public Time time; // 时间
    public String TranscationDescription; // 账目说明
    public double money; // 资金
    public boolean flag; // 是否被扔掉

    // 无参数构造方法 写无参构造方法的目的是为了更好的调用 这个类的功能方法
    public Record(){} 
    // 有参构造方法
    public Record(Time time, String TranscationDescription, double money){
        this.time = time;
        this.TranscationDescription = TranscationDescription;
        this.money = money;
        this.flag = false;
    }
}

这样就解决了第一问的需求。

2.项目方法的加入

请添加图片描述
请添加图片描述

结合2,3两点可以知晓,需要创建一个可以生成随机账目的方法,我们命名为Record [] RandomAccount(),属于Record的方法。

// 产生随机账单的方法
    public Record [] RandomAccount(){
        // 生产随机数种子
        Random r = new Random();
        // 定义随机数组 题目要求三组
        Record [] records = new Record[3];

        // 定义时间类 来生成随机时间
        Time time = new Time().RandomTime();
        for (int i = 0; i < 3; ++ i){
            Time time0 = new Time().RandomTime();    // 生成随机时间
            int money0 = new Record().RandomMoney(); // 生成随机金额
            String TranscationDescription0;

            // 如果金额>0那么就是收入 反之就是支出
            if (money0 > 0) TranscationDescription0 = "收入" + i;
            else TranscationDescription0 = "支出" + i;

            // 给数组赋值
            records[i] = new Record(time0, TranscationDescription0, money0);
        }
        return records;
    }

对于Record [] RandomAccount()方法,里面设计的时候需要添加其他方法来辅助完成,比如随机生成日期的RandomTime()方法,这个方法属于Time类。

// 生成随机日期值
    public Time RandomTime(){
        // 引入随机种子
        Random r = new Random();

        // 月份数组
        int Months [] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
        int month = Months[r.nextInt(12)]; // 在12个月里面选一个
        int day; // 天数

        // 生成随机天数
        if (isBigMonth(month)){ // 如果是大月
            day = r.nextInt(31) + 1; // 生成范围1~31
        } else if (isSmallMonth(month)) { // 如果是小月
            day = r.nextInt(30) + 1; // 生成范围1~30
        } else { // 如果是特殊月份 2月
            day = r.nextInt(28) + 1; // 生成范围1~28
        }

        return new Time(month, day);
    }

对于该方法也需要一定的辅助方法,各个判断大小月份的方法。

	// 判断是否为大月
    public boolean isBigMonth(int month){
        if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) return true;
        return false;
    }

    // 判断是否为小月
    public boolean isSmallMonth(int month){
        if (month == 4 || month == 6 || month == 11) return true;
        return false;
    }

此刻2,3点的需求就基本完成了。

然后看最后一点

请添加图片描述

分析4可知,这个方法的目的是返回差异数组。

我们设计为Record [] FindDifferentBills(Record[] r1, Record[] r2)

public Record [] FindDifferentBills(Record[] r1, Record[] r2){
        int cnt = 0; // 记录不同的单子数
        for (int i = 0; i < 3; ++ i){
            for (int j = 0; j < 3; ++ j){
                if (r1[i].flag == true || r2[j].flag == true) continue; // 如果比较的记录里面存在 已经需要离开的了
                if (CheckRecord(r1[i], r2[j])) { // 如果两个记录金额相等
                    r1[i].flag = true; // 那么把这个单子置为true
                    r2[j].flag = true;
                }
            }
        }

        // 筛选出还是false的单子的数量
        for (int i = 0; i < 3; ++ i){
            if (r1[i].flag == false) cnt ++;
        }
        for (int i = 0; i < 3; ++ i){
            if (r2[i].flag == false) cnt ++;
        }

        // System.out.println(cnt);
        // 存储最后的结果 长度为cnt
        Record [] DiffResults = new Record [cnt];
        int cnt2 = 0;

        // 筛选出还是false的单子
        for (int i = 0; i < 3; ++ i){
            if (r1[i].flag == false) DiffResults[cnt2 ++] = r1[i];
        }
        for (int i = 0; i < 3; ++ i){
            if (r2[i].flag == false) DiffResults[cnt2 ++] = r2[i];
        }

        // 自定义排序方法 是的结果符合按日期顺序
        Comparator cmp = new MyComparator();
        Arrays.sort(DiffResults, cmp);
        return DiffResults;
    }

该方法说涉及的其他方法为Record类的boolean CheckRecord(Record record1, Record record2),判断两个record是否相等。

// 对比账单方法
    public boolean CheckRecord(Record record1, Record record2){
        // 程序需要按照⾦额项对比,剔除匹配项并寻找所有差异项输出 // 这是根据题目的这句话设计的
        if (record1.money == record2.money) return true;
        return false;
    }

到这里基本就把这个类设计完成了,最后再两个类中加上打印的方法,方便显示,基本就没有问题了。

3.测试类的编写

// 测试类
public class Main{
    public static void main(String [] args){
        // 银行账单
        Record[] bankRecords = new Record().RandomAccount();
//        for (int i = 0; i < 3; i++) {
//            bankRecords[i].PrintRecord(bankRecords[i]);
//        }

        // 创建企业账单
        Record[] companyRecords = new Record().RandomAccount();
//        for (int i = 0; i < 3; i++) {
//            companyRecords[i].PrintRecord(companyRecords[i]);
//        }

        Record [] DiffResults = new Record().FindDifferentBills(bankRecords, companyRecords);

        // 最后的筛选结果
        for (Record record : DiffResults){
            record.PrintRecord(record);
        }
    }
}

4.汇总

import java.util.Arrays;
import java.util.Comparator;
import java.util.Random;

// 多写注释是一个好习惯 很多大厂都有检查程序员写注释的比赛
// 辅助时间类
// 改日期以平年为例子
class Time{
    // 最好成员设置为私有 然后设置对应的get set方法这样更符合面相对象的封装思想
    public int month; // 月
    public int day; // 日

    // 无参数构造方法 写无参构造方法的目的是为了更好的调用 这个类的功能方法
    public Time(){}

    // 有参构造方法
    public Time(int month, int day){
        this.month = month;
        this.day = day;
    }

    // 输出时间
    public void PrintTime(){
        System.out.print(this.month+"月" + this.day + "日");
    }

    // 判断是否为大月
    public boolean isBigMonth(int month){
        if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) return true;
        return false;
    }

    // 判断是否为小月
    public boolean isSmallMonth(int month){
        if (month == 4 || month == 6 || month == 11) return true;
        return false;
    }

    // 生成随机日期值
    public Time RandomTime(){
        // 引入随机种子
        Random r = new Random();

        // 月份数组
        int Months [] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
        int month = Months[r.nextInt(12)]; // 在12个月里面选一个
        int day; // 天数

        // 生成随机天数
        if (isBigMonth(month)){ // 如果是大月
            day = r.nextInt(31) + 1; // 生成范围1~31
        } else if (isSmallMonth(month)) { // 如果是小月
            day = r.nextInt(30) + 1; // 生成范围1~30
        } else { // 如果是特殊月份 2月
            day = r.nextInt(28) + 1; // 生成范围1~28
        }

        return new Time(month, day);
    }

    // 对比两个时间先后的方法 如果前者小于后者的话 那么返回1 反之 -1如果一样返回0 这个为顺序
    public int CompareTime(Time t1, Time t2){
        int num;
        if (t1.month < t2.month) num = -1;
        else if (t1.month > t2.month) num = 1;
        else
        {
            if (t1.day < t2.day) num = -1;
            else if (t1.day > t2.day) num = 1;
            else num = 0;
        }
        return num;
    }
}

// 使用类Record存储账单记录信息,包括:时间、交易说明和⾦额
class Record{
    // 最好成员设置为私有 然后设置对应的get set方法这样更符合面相对象的封装思想

    public Time time; // 时间
    public String TranscationDescription; // 账目说明
    public double money; // 资金
    public boolean flag; // 是否被扔掉

    public Record(){}
    // 有参构造方法
    public Record(Time time, String TranscationDescription, double money){
        this.time = time;
        this.TranscationDescription = TranscationDescription;
        this.money = money;
        this.flag = false;
    }

    // 生成随机金额
    public int RandomMoney(){
        // 引入随机种子
        Random r = new Random();
        int money = r.nextInt(601) - 300; // 生成的范围是-300~300的金额
        while(money == 0) money = r.nextInt(601) - 300; // 防止是生成的是0 没有什么意义这个数字 这里有一个强制类型转换int to double
        return money;
    }

    // 产生随机账单的方法
    public Record [] RandomAccount(){
        // 生产随机数种子
        Random r = new Random();
        // 定义随机数组 题目要求三组
        Record [] records = new Record[3];

        // 定义时间类 来生成随机时间
        Time time = new Time().RandomTime();
        for (int i = 0; i < 3; ++ i){
            Time time0 = new Time().RandomTime();    // 生成随机时间
            int money0 = new Record().RandomMoney(); // 生成随机金额
            String TranscationDescription0;

            // 如果金额>0那么就是收入 反之就是支出
            if (money0 > 0) TranscationDescription0 = "收入" + i;
            else TranscationDescription0 = "支出" + i;

            // 给数组赋值
            records[i] = new Record(time0, TranscationDescription0, money0);
        }
        return records;
    }

        // 对比账单方法
        public boolean CheckRecord(Record record1, Record record2){
            // 程序需要按照⾦额项对比,剔除匹配项并寻找所有差异项输出 // 这是根据题目的这句话设计的
            if (record1.money == record2.money) return true;
            return false;
        }

    // 打印账单
    public void PrintRecord(Record record){
        // 打印时间

        System.out.print("时间:");
        record.time.PrintTime();
        System.out.print(" 金额:" + record.money + " ");
        System.out.println("说明:" + record.TranscationDescription);
    }

    // 寻找两个账单中不同的地方
    public Record [] FindDifferentBills(Record[] r1, Record[] r2){
        int cnt = 0; // 记录不同的单子数
        for (int i = 0; i < 3; ++ i){
            for (int j = 0; j < 3; ++ j){
                if (r1[i].flag == true || r2[j].flag == true) continue; // 如果比较的记录里面存在 已经需要离开的了
                if (CheckRecord(r1[i], r2[j])) { // 如果两个记录金额相等
                    r1[i].flag = true; // 那么把这个单子置为true
                    r2[j].flag = true;
                }
            }
        }

        // 筛选出还是false的单子的数量
        for (int i = 0; i < 3; ++ i){
            if (r1[i].flag == false) cnt ++;
        }
        for (int i = 0; i < 3; ++ i){
            if (r2[i].flag == false) cnt ++;
        }

        // System.out.println(cnt);
        // 存储最后的结果 长度为cnt
        Record [] DiffResults = new Record [cnt];
        int cnt2 = 0;

        // 筛选出还是false的单子
        for (int i = 0; i < 3; ++ i){
            if (r1[i].flag == false) DiffResults[cnt2 ++] = r1[i];
        }
        for (int i = 0; i < 3; ++ i){
            if (r2[i].flag == false) DiffResults[cnt2 ++] = r2[i];
        }

        // 自定义排序方法
        Comparator cmp = new MyComparator();
        Arrays.sort(DiffResults, cmp);
        return DiffResults;
    }

    // 自定义排序接口 账单Record的排序方法为 Time的顺序
    class MyComparator implements Comparator<Record> {

        @Override
        public int compare(Record o1, Record o2) {
            int num = new Time().CompareTime(o1.time, o2.time);
            return num;
        }
    }
}

// 测试类
public class Main{
    public static void main(String [] args){
        // 银行账单
        Record[] bankRecords = new Record().RandomAccount();
//        for (int i = 0; i < 3; i++) {
//            bankRecords[i].PrintRecord(bankRecords[i]);
//        }

        // 创建企业账单
        Record[] companyRecords = new Record().RandomAccount();
//        for (int i = 0; i < 3; i++) {
//            companyRecords[i].PrintRecord(companyRecords[i]);
//        }

        Record [] DiffResults = new Record().FindDifferentBills(bankRecords, companyRecords);

        // 最后的筛选结果
        for (Record record : DiffResults){
            record.PrintRecord(record);
        }
    }
}

运行结果
请添加图片描述