(2022级)成都工业学院软件构造实验三:面向数据的软件构造

写在前面

1、基于2022级软件工程实验指导书

2、代码仅提供参考

3、如果代码不满足你的要求,请寻求其他的途径

运行环境

window11家庭版

IntelliJ IDEA 2023.2.2

jdk17.0.6

实验要求

任务:

‍一、构造任务4:批量产生习题并用文件存储。

二、构造任务6:批改练习并存储

三、构造任务5:生成100以内加法/减法的算式

以下为详细说明:

一、构造任务4:批量产生习题并用文件存储。

构造任务4.2.1:以第3章面向对象的版本为基础,完成构造任务4,建议新加一个类ExerciseFiles、增加方法,批量产生并存储习题(CSV文件格式)。

要求:

截屏和.txt文件,内容是CSV格式的练习题(20~50题),加、减、混合题各一套;

构造任务4.2.2:复用BinaryOperation, Exercise, ExerciseSheet,建议新加一个类ExerciseFiles、在其中增加方法,从CSV格式的文件中读入习题。

下面是4个CSV加法、减法练习文件,有的文件格式无任何多余符号、有的文件中有无关符号

文件1:exercise_add_50_1

文件2:exercise_add_70_2

文件3:exercise_sub_50_1

文件4:exercise_sub_60_2

要求:读入教师指定的上述4套CSV格式的练习文件并相应处理,按照3~5列:

2.1 屏幕显示读到的文件内容。

2.2 在上述基础上添加运算结果,例如33+22=55,屏幕显示,要求复用第三章的算式类;

技术考核点:

  1. 防御性编程

1.1 异常的使用和处理,比如不存在的文件、数值超出范围或者不满足约束条件;

1.2 练习文件中包含无关符号、要用正则表达式处理;

  1. junit的使用

2.1 测试异常,成功和失败各一次

2.2 参数化测试

2.3 测试套件

二、构造任务6:批改练习并存储。

练习结果以CSV格式写入一个练习文件;程序读入该文件,与相应习题中的每个算式答案比较;统计批改,屏幕显示,同时存入CSV格式的批改文件。练习结果文件的参考格式:

文件名:answers_add_50_19

76,65,61, 58,78,42,45,-1, 56, 63,...

要求练习答案的顺序和数目与对应的习题一致。对于没有做出的算式,录入到CSV文件时,用1表示。批改、统计练习后,存储文件的参考格式:

练习题:文件名

算式总数:50

正确:45

错误:5

得分:90

dd_50_3 exercise_add_50_3

Test2: answers_mix_70_3 exercise_ mix _70_3

功能考核点:

  1. 读入CSV格式的练习exercise文件,简单防御性处理:两者数量不一致,文件不存在,打不开文件(或者不是CSV格式);

屏幕输出读入的文件、截屏显示

  1. 从exercise中计算每一个算式的结果,要求复用第三章的算式类

屏幕输出每一个算式的结果、截屏显示

  1. 批改练习:检查结果是否正确,记录统计结果,屏幕输出或存入CSV格式的文件,给出证据

三、构造任务5:生成100以内加法/减法的算式基。

新加一个类BinaryOperationBase,产生算式基、存储到文件,从算式基随机选择算式组成练习,

考核点及验证:

  1. 分别生产正确的加法算式基、减法算式基;验证:2个截屏(数值范围可以是20)。
  2. 要求复用第三章的类,否则本题不得分。

加法算式基、减法算式基分别存入CSV格式的文件;

验证:CSV格式的2个文件。​

从CSV格式的读入算式基、并分别组成一定数量练习;

验证:35道加法算式、48道减法算式,截屏。

  1. 把加法算式基和减法算式基合并在一个数据结构,存入CSV格式的文件,并且从中组成一定数量练习;验证:一个截屏和CSV格式的文件,50题混合算式的练习,截屏。

不完成3个任务、要求复用第三章的类,否则本题不得分。

源代码

BinaryOperation.java

import java.util.*;

abstract class BinaryOperation {
    protected int operand1;
    protected int operand2;
    protected int result;

    public BinaryOperation() {
        // 生成操作数和计算结果
        Random rand = new Random();
        operand1 = rand.nextInt(101); // 生成0到100的随机数
        operand2 = generateOperand2();
        result = operate(operand1, operand2);
    }

    protected abstract int operate(int operand1, int operand2);

    // 生成第二个操作数
    protected abstract int generateOperand2();

    public String getExpression() {
        return operand1 + "\t" + getOperator() + "\t" + operand2 + "\t" + " = ";
    }

    protected abstract String getOperator();

    public int getResult() {
        return result;
    }
}

// 加法类
class Addition extends BinaryOperation {
    @Override
    protected int operate(int operand1, int operand2) {
        return operand1 + operand2;
    }

    @Override
    protected int generateOperand2() {
        Random rand = new Random();
        return rand.nextInt(101 - operand1); // 第二个操作数不能超过100减去第一个操作数
    }

    @Override
    protected String getOperator() {
        return " + ";
    }
}

// 减法类
class Subtraction extends BinaryOperation {
    @Override
    protected int operate(int operand1, int operand2) {
        return operand1 - operand2;
    }

    @Override
    protected int generateOperand2() {
        Random rand = new Random();
        return rand.nextInt(operand1 + 1); // 第二个操作数不能超过第一个操作数
    }

    @Override
    protected String getOperator() {
        return " - ";
    }
}

Exercise.java

//构造要求2:实现Exercise
class Exercise {
    private BinaryOperation operation;

    public Exercise(BinaryOperation operation) {
        this.operation = operation;
    }

    public String getExpression() {
        return operation.getExpression();
    }

    public int getResult() {
        return operation.getResult();
    }
}

ExerciseSheet.java

import java.util.HashSet;
import java.util.Set;

//构造要求2:实现ExerciseSheet
class ExerciseSheet {
    private Exercise[] exercises;

    public ExerciseSheet(int numExercises, Class<? extends BinaryOperation> operationType) {
        exercises = new Exercise[numExercises];
        try {
            Set<String> expressions = new HashSet<>(); // 使用集合来确保题目不重复
            for (int i = 0; i < numExercises; i++) {
                BinaryOperation operation = operationType.newInstance();
                String expression = operation.getExpression();
                // 如果集合中已经有了相同的表达式,则重新生成直到不重复为止
                while (expressions.contains(expression)) {
                    operation = operationType.newInstance();
                    expression = operation.getExpression();
                }
                expressions.add(expression);
                exercises[i] = new Exercise(operation);
            }
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public Exercise[] getExercises() {
        return exercises;
    }
}

ExerciseFIles.java

import java.io.*;
import java.util.Random;
//构造任务1:批量产生习题并用文件存储
public class ExerciseFiles {
    private static final int NUM_EXERCISES = 50;

    // 生成加法练习题并写入CSV文件
    public static void generateAdditionCSV(String filename) {
        generateCSV(filename, Addition.class);
    }

    // 生成减法练习题并写入CSV文件
    public static void generateSubtractionCSV(String filename) {
        generateCSV(filename, Subtraction.class);
    }

    // 生成加减混合练习题并写入CSV文件
    public static void generateMixedOperationCSV(String filename) {
        try (PrintWriter writer = new PrintWriter(new FileWriter(filename))) {
            Random rand = new Random();
            for (int i = 0; i < NUM_EXERCISES; i++) {
                Class<? extends BinaryOperation> operationType = rand.nextBoolean() ? Addition.class : Subtraction.class;
                ExerciseSheet sheet = new ExerciseSheet(1, operationType);
                Exercise[] exercises = sheet.getExercises();
                writer.println(exercises[0].getExpression());
            }
            System.out.println("CSV文件已生成:" + filename);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    // 生成CSV文件
    private static void generateCSV(String filename, Class<? extends BinaryOperation> operationType) {
        try (PrintWriter writer = new PrintWriter(new FileWriter(filename))) {
            ExerciseSheet sheet = new ExerciseSheet(NUM_EXERCISES, operationType);
            Exercise[] exercises = sheet.getExercises();
            for (Exercise exercise : exercises) {
                writer.println(exercise.getExpression());
            }
            System.out.println("CSV文件已生成:" + filename);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 读取并计算CSV文件中的算式
    public static void calculateAndPrintCSV(String filename) {
        try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
            String line;
            int count = 0; // 记录已输出的算式数量
            while ((line = reader.readLine()) != null) {
                // 对每一行数据进行预处理,去除可能存在的额外空格
                line = line.trim().replaceAll("\\s+", "\t");
                String[] parts = line.split("\t");
                int operand1 = Integer.parseInt(parts[0]);
                int operand2 = Integer.parseInt(parts[2]);
                String operator = parts[1];
                int result;

                // 判断运算符并进行相应的计算
                switch (operator) {
                    case "+":
                        result = operand1 + operand2;
                        break;
                    case "-":
                        result = operand1 - operand2;
                        break;
                    default:
                        System.out.println("警告:不支持的运算符:" + operator);
                        continue; // 跳过本次循环,继续处理下一个算式
                }

                // 输出算式及其结果
                System.out.printf("%-10s", line + result + "\t\t");
                count++;
                if (count % 5 == 0) // 每行五个算式
                    System.out.println();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void generateAll() {
        // 生成加法练习题CSV文件
        ExerciseFiles.generateAdditionCSV("addition_exercises.csv");

        // 生成减法练习题CSV文件
        ExerciseFiles.generateSubtractionCSV("subtraction_exercises.csv");

        // 生成加减混合练习题CSV文件
        ExerciseFiles.generateMixedOperationCSV("mixed_operation_exercises.csv");
    }

    public static void calculateAndPrintAll() {
        // 读取并计算加法练习题CSV文件
        System.out.println("读取并计算加法练习题CSV文件:");
        ExerciseFiles.calculateAndPrintCSV("addition_exercises.csv");

        // 读取并计算减法练习题CSV文件
        System.out.println("\n读取并计算减法练习题CSV文件:");
        ExerciseFiles.calculateAndPrintCSV("subtraction_exercises.csv");

        // 读取并计算加减混合练习题CSV文件
        System.out.println("\n读取并计算加减混合练习题CSV文件:");
        ExerciseFiles.calculateAndPrintCSV("mixed_operation_exercises.csv");
    }

}

ExerciseCorrection.java

import java.io.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
//构造任务2:批改练习并存储
public class ExerciseCorrection {
    // 从文件中读取习题
    private static List<String> readExercisesFromFile(String filename) throws IOException {
        List<String> exerciseList = new ArrayList<>();
        try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
            String line;
            while ((line = reader.readLine()) != null) {
                exerciseList.add(line);
            }
        }
        return exerciseList;
    }

    // 获取用户输入的答案
    private static List<Integer> getUserAnswers(List<String> exerciseList) {
        List<Integer> userAnswers = new ArrayList<>();
        Scanner scanner = new Scanner(System.in);
        for (int i = 0; i < exerciseList.size(); i++) {
            String exercise = exerciseList.get(i);
            System.out.println("第 " + (i + 1) + " 题:" + exercise);
            String userInput = scanner.nextLine();
            try {
                int answer = Integer.parseInt(userInput);
                userAnswers.add(answer);
            } catch (NumberFormatException e) {
                userAnswers.add(-1);
            }
        }
        return userAnswers;
    }

    // 写入用户答案到文件
    private static void writeAnswersToFile(List<Integer> userAnswers, String filename) throws IOException {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(filename))) {
            for (Integer answer : userAnswers) {
                writer.write(answer + ",");
            }
            writer.newLine();
        }
    }

    // 批改并统计结果
    private static void correctAndReport(List<String> exerciseList, List<Integer> answersList, List<Integer> userAnswersList) {
        int totalExercises = exerciseList.size();
        if (totalExercises == 0 || answersList.size() == 0 || userAnswersList.size() == 0) {
            System.out.println("习题文件或答案文件为空,请检查文件内容。");
            return;
        }

        int correctCount = 0;
        for (int i = 0; i < totalExercises; i++) {
            int correctAnswer = evaluateExpression(exerciseList.get(i));
            int userAnswer = userAnswersList.get(i);
            if (userAnswer == correctAnswer) {
                correctCount++;
            }
        }

        // 统计结果
        int incorrectCount = totalExercises - correctCount;
        int score = (int) ((double) correctCount / totalExercises * 100);

        System.out.println("算式批改结果已存入文件");
        // 写入批改结果到文件
        try (BufferedWriter writer = new BufferedWriter(new FileWriter("correction_results.csv"))) {
            writer.write("练习题:" + "user_answers.csv");
            writer.newLine();
            writer.write("算式总数:" + totalExercises);
            writer.newLine();
            writer.write("正确:" + correctCount);
            writer.newLine();
            writer.write("错误:" + incorrectCount);
            writer.newLine();
            writer.write("得分:" + score);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 计算表达式的值
    private static int evaluateExpression(String expression) {
        // 使用正则表达式匹配数字和运算符,忽略不可见的空白字符
        Pattern pattern = Pattern.compile("\\s*(\\d+)\\s*([-+])\\s*(\\d+)\\s*=\\s*");
        Matcher matcher = pattern.matcher(expression);
        if (matcher.matches()) {
            int operand1 = Integer.parseInt(matcher.group(1));
            String operator = matcher.group(2);
            int operand2 = Integer.parseInt(matcher.group(3));

            if (operator.equals("+")) {
                return operand1 + operand2;
            } else if (operator.equals("-")) {
                return operand1 - operand2;
            }
        }
        return 0;
    }

    public static void menu() {
        Scanner scanner = new Scanner(System.in);
        // 用户选择习题文件类型
        System.out.println("请选择习题文件类型:");
        System.out.println("1. 加法习题");
        System.out.println("2. 减法习题");
        System.out.println("3. 混合运算习题");
        System.out.print("请选择:");
        int choice = scanner.nextInt();
        String exerciseFilename = "";
        switch (choice) {
            case 1:
                exerciseFilename = "addition_exercises.csv";
                break;
            case 2:
                exerciseFilename = "subtraction_exercises.csv";
                break;
            case 3:
                exerciseFilename = "mixed_operation_exercises.csv";
                break;
            default:
                System.out.println("无效选择。");
                System.exit(-1);
        }
        String answersFilename = "user_answers.csv";
        try {
            List<String> exerciseList = readExercisesFromFile(exerciseFilename);

            // 获取用户输入答案
            List<Integer> userAnswersList = getUserAnswers(exerciseList);

            // 写入用户答案到文件
            writeAnswersToFile(userAnswersList, answersFilename);

            // 从文件中读取正确答案
            List<Integer> answersList = new ArrayList<>();
            try (BufferedReader reader = new BufferedReader(new FileReader(answersFilename))) {
                String line = reader.readLine();
                if (line != null) {
                    String[] answersArray = line.split(",");
                    for (String answer : answersArray) {
                        answersList.add(Integer.parseInt(answer));
                    }
                }
            }

            // 批改并统计结果
            correctAndReport(exerciseList, answersList, userAnswersList);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

BinaryOperationBase.java

import java.io.*;
import java.util.*;
//构造任务3:生成100以内加法/减法的算式
public class BinaryOperationBase {
    private List<String> additionBase;
    private List<String> subtractionBase;

    public BinaryOperationBase() {
        this.additionBase = new ArrayList<>();
        this.subtractionBase = new ArrayList<>();
    }

    // 生成加法算式基
    public void generateAdditionBase(int numOperations) {
        for (int i = 0; i < numOperations; i++) {
            BinaryOperation addition = new Addition();
            additionBase.add(addition.getExpression() + addition.getResult());
        }
    }

    // 生成减法算式基
    public void generateSubtractionBase(int numOperations) {
        for (int i = 0; i < numOperations; i++) {
            BinaryOperation subtraction = new Subtraction();
            subtractionBase.add(subtraction.getExpression() + subtraction.getResult());
        }
    }

    // 生成混合算式基
    public void generateMixedOperationBase(int numOperations) {
        generateAdditionBase(numOperations / 2);
        generateSubtractionBase(numOperations / 2);
    }

    // 将加法算式基存储到文件
    public void saveAdditionBaseToFile(String filename) {
        saveBaseToFile(additionBase, filename);
    }

    // 将减法算式基存储到文件
    public void saveSubtractionBaseToFile(String filename) {
        saveBaseToFile(subtractionBase, filename);
    }

    // 将算式基存储到文件
    private void saveBaseToFile(List<String> base, String filename) {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(filename))) {
            for (String operation : base) {
                writer.write(operation);
                writer.newLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 从加法算式基中随机选择指定数量的算式
    public List<String> getRandomAdditionOperations(int numOperations) {
        return getRandomOperations(additionBase, numOperations);
    }

    // 从减法算式基中随机选择指定数量的算式
    public List<String> getRandomSubtractionOperations(int numOperations) {
        return getRandomOperations(subtractionBase, numOperations);
    }

    // 从混合算式基中随机选择指定数量的算式
    public List<String> getRandomMixedOperationOperations(int numOperations) {
        List<String> mixedOperations = new ArrayList<>();
        mixedOperations.addAll(additionBase);
        mixedOperations.addAll(subtractionBase);
        Collections.shuffle(mixedOperations);
        return mixedOperations.subList(0, numOperations);
    }

    // 从算式基中随机选择指定数量的算式
    private List<String> getRandomOperations(List<String> base, int numOperations) {
        List<String> randomOperations = new ArrayList<>();
        Random rand = new Random();
        for (int i = 0; i < numOperations; i++) {
            int index = rand.nextInt(base.size());
            randomOperations.add(base.get(index));
        }
        return randomOperations;
    }

    public static void menu() {
        BinaryOperationBase base = new BinaryOperationBase();

        // 生成加法算式基并存储到文件
        base.generateAdditionBase(100);
        System.out.println("加法算式基已生成");
        base.saveAdditionBaseToFile("addition_base.csv");
        System.out.println("加法算式基已存入文件");
        // 生成减法算式基并存储到文件
        base.generateSubtractionBase(100);
        System.out.println("减法算式基已生成");
        base.saveSubtractionBaseToFile("subtraction_base.csv");
        System.out.println("减法算式基已存入文件");

        // 生成混合算式基并存储到文件
        base.generateMixedOperationBase(100);
        System.out.println("混合算式基已生成");
        base.saveSubtractionBaseToFile("mixed_operation_base.csv");
        System.out.println("混合算式基已存入文件");

        // 从随机抽取的算式基中随机选择50个算式
        List<String> randomAdditionOperations = base.getRandomAdditionOperations(50);
        List<String> randomSubtractionOperations = base.getRandomSubtractionOperations(50);
        List<String> randomMixedOperations = base.getRandomMixedOperationOperations(50);

        // 将随机抽取的算式存入对应的CSV文件中
        base.saveBaseToFile(randomAdditionOperations, "addition_exercises.csv");
        base.saveBaseToFile(randomSubtractionOperations, "subtraction_exercises.csv");
        base.saveBaseToFile(randomMixedOperations, "mixed_operation_exercises.csv");
    }
}

Main.java

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int choice = -1;
        while (choice != 0) {
            System.out.println("请输入你的选择:");
            System.out.println("1、批量产生习题并用文件存储");
            System.out.println("2、读入习题并添加答案");
            System.out.println("3、批改练习并储存");
            System.out.println("4、生成算式基并用文件储存");
            System.out.println("0、退出");
            System.out.printf("你的选择是:");
            if (scanner.hasNextInt()) {
                choice = scanner.nextInt();
                switch (choice) {
                    case 1:
                        ExerciseFiles exerciseFiles = new ExerciseFiles();
                        exerciseFiles.generateAll();
                        break;
                    case 2:
                        ExerciseFiles exerciseFiles1 = new ExerciseFiles();
                        exerciseFiles1.calculateAndPrintAll();
                        break;
                    case 3:
                        ExerciseCorrection exerciseCorrection = new ExerciseCorrection();
                        exerciseCorrection.menu();
                        break;
                    case 4:
                        BinaryOperationBase binaryOperationBase = new BinaryOperationBase();
                        binaryOperationBase.menu();
                        break;
                    case 0:
                        System.out.println("程序已退出。");
                        break;
                    default:
                        System.out.println("无效的选项,请重新输入。");
                        break;
                }
            } else {
                System.out.println("输入无效,请重新输入数字选项。");
                scanner.next(); // 消耗无效输入
            }
        }
    }
}

运行结果

相关推荐
豆豆3 天前
如何选择国产化CMS来建设政务网站?
服务器·开发语言·前端·php·软件构建·政务
豆豆9 天前
如何选择企业网站模版来搭建网站?
服务器·开发语言·前端·php·软件构建
李启柱16 天前
项目开发流程规范文档
运维·软件构建·个人开发·设计规范
帅次23 天前
基于云平台的智能家居管理系统设计与通信协议分析
设计模式·重构·软件工程·软件构建·需求分析·代码规范·设计规范
帅次25 天前
基于边缘计算的智能门禁系统架构设计分析
软件工程·团队开发·软件构建·需求分析·规格说明书·代码复审·极限编程
豆豆1 个月前
如何制作一个自己的网站?
服务器·开发语言·前端·php·软件构建
豆豆1 个月前
如何选择适合自己搭建网站的CMS?
服务器·开发语言·前端·php·软件构建
大只因bug1 个月前
基于springboot美食商城推荐系统
spring boot·后端·mysql·系统架构·前端框架·软件构建·美食
qq_535246141 个月前
代码随想录 117. 软件构建
c++·算法·软件构建
*.✧屠苏隐遥(ノ◕ヮ◕)ノ*.✧1 个月前
软件设计模式------抽象工厂模式
设计模式·软件构建·个人开发·抽象工厂模式·uml·开闭原则