JAVA第一次Blog作业

目录

前言

设计与分析

PTA第一次作业

PTA第二次作业

PTA第三次作业

踩坑心得

改进建议

总结

前言
 本学期已经学习JAVA一个多月的时间,对比上学期所学习的C语言,JAVA更加方便和更好理解。最开始起步困难,想不出来从何入手JAVA程序,一直用C语言的思路来写JAVA程序,没有领悟到面对“对象”程序设计中对象的含义,依旧是面向过程进行整体的程序设计。现在略微掌握了JAVA的基本思路,期望经过之后的进一步学习,最后熟练掌握JAVA。
 PTA的前三次作业在知识点上逐渐深入,逐步展现出面向对象的特性,每次作业的前面几个题目的难度都适中,最后一题的答题判题程序才是每次OOP作业的重难点,也因此它的得分很重。虽然两次次作业我都得了满分,但实际上我所写的代码即使经过了繁琐的细节思考和逻辑思考,依旧有很多不足之处。以下是对三次PTA作业的概要分析。
设计与分析
PTA第一次作业
类图:

对于这个答题判题程序的设计,可以将其拆分为几个主要的部分来处理:题目管理、答题管理以及判题逻辑。下面我将对这些部分进行详细说明。
题目管理
首先,我们需要一个类来表示单个题目,包括题号、题目内容和标准答案。这里我们定义一个Question类。
Question类
属性:
id:题号
content:题目内容
standardAnswer:标准答案
方法:
get/setId:获取/设置题号
getContent:获取题目内容
getStandardAnswer:获取标准答案
checkAnswer(answer):检查提供的答案answer是否与标准答案匹配,返回布尔值
答卷管理
接下来,需要一个类来管理整个试卷,包括所有的问题和答题信息。这可以通过创建一个Exam类来实现。
Exam类
属性:
questions:一个字典或列表,用于存储Question对象,键为题号,值为对应的Question对象
answers:一个字典,用于存储用户提交的答案,键为题号,值为用户答案
judgments:一个列表,用于存储每个题目的判题结果(true或false)
方法:
addQuestion(question):向试卷中添加一个问题
addAnswer(id, answer):为指定题号添加答案
judgeAnswers():对所有答案进行判题,并更新judgments列表
printResults():打印每个题目的内容、用户答案及判题结果
判题逻辑
在Exam类中,judgeAnswers方法将遍历所有的题目,调用每个Question对象的checkAnswer方法来比较用户答案与标准答案。如果匹配,则在judgments列表中添加true,否则添加false。
实现流程
读取题目数量:从输入中读取题目数量。
读取题目内容:根据题目数量循环读取题目内容,创建Question对象并使用Exam对象的addQuestion方法将其加入试卷。
读取答题信息:继续读取直到遇到end,将每个答案通过Exam对象的addAnswer方法保存。
判题:调用Exam对象的judgeAnswers方法进行判题。
输出结果:调用Exam对象的printResults方法输出题目内容、用户答案及判题结果。
注意事项
在处理输入时,需要注意去除多余的空格。
题目和答案的输入顺序可能与题号无关,因此在处理时需要确保能够正确地将答案与题目对应起来。
输出时,题目内容和答案之间使用~连接。
心得
在设计此类程序时,模块化是一个非常重要的概念。通过将功能分解成不同的类和方法,可以使代码更加清晰易懂,同时也便于维护和扩展。此外,良好的错误处理机制也是必不可少的,它可以帮助我们更早地发现和解决问题。在这个过程中,细心和耐心是非常重要的品质,因为细节上的疏忽往往会导致程序出现错误。

//核心部分:
public Question parseQuestion(String line) {
        // 去除多余的空格
        line = line.replaceAll("\\s+", " ").trim();
        
        Pattern pattern = Pattern.compile("#N:(\\d+) #Q:(.*?) #A:(.*)");
        Matcher matcher = pattern.matcher(line);

        if (matcher.find()) {
            int number = Integer.parseInt(matcher.group(1));
            String content = matcher.group(2).trim();
            String answer = matcher.group(3).trim();
            return new Question(number, content, answer);
        } else {
            throw new IllegalArgumentException("题目格式错误,应为 '#N:题号 #Q:题目内容 #A:标准答案'");
        }
    }

PTA第二次作业
类图
1.思路
根据题目要求,我们需要实现一个考试系统,能够处理以下三类信息:
题目信息:包括题号、题目内容和标准答案。
试卷信息:包括试卷号、题目编号和分值。
答卷信息:包括试卷号和用户答案。
系统需要能够:
读取并解析输入信息。
根据标准答案判断用户答案的正确性。
计算每道题的得分和总分。
输出判题结果和得分信息。
处理特殊情况,如试卷总分不等于100分、答案缺失、无效试卷号等。
2. 类设计
Question:表示题目,包含题号、题目内容和标准答案。
属性:
number:题号
content:题目内容
standardAnswer:标准答案
方法:
checkAnswer(String answer):检查用户答案是否正确
TestPaper:表示试卷,包含试卷号、题目列表和分值信息。
属性:
number:试卷号
questions:题目列表,键为题号,值为 Question 对象
scores:题目分值,键为题号,值为分值
方法:
addQuestion(Question question, int score):添加题目和分值
getTotalScore():计算试卷总分
getQuestions():获取题目列表
getScores():获取分值列表
getNumber():获取试卷号
Exam:表示考试系统,管理题目和试卷,处理答题信息并输出结果。
属性:
questions:题目列表,键为题号,值为 Question 对象
testPapers:试卷列表,键为试卷号,值为 TestPaper 对象
ExamSystem:主类,负责读取输入、解析数据并调用 Exam 类进行处理。
方法:
addQuestion(Question question):添加题目
addTestPaper(TestPaper testPaper):添加试卷
gradeTestPaper(int testPaperNum, Map<Integer, String> answers):判题并输出结果
checkTotalScore():检查试卷总分是否为100分
PTA第三次作业
类图:

分析需求
题目信息:需要存储题目的编号、题目内容及标准答案。
试卷信息:需要关联题目编号与分数,构建试卷结构。
学生信息:需要保存学生的学号和姓名。
答卷信息:需要根据学生的学号和试卷号匹配学生对试卷的回答,并计算成绩。
删除题目信息:需要能够从题目信息中移除指定的题目,并影响相关试卷的评分。
错误处理:包括格式错误、试卷号或学号引用错误、题目不存在等异常情况。
设计方案
数据结构设计
题目信息:可以使用字典存储,键为题目编号,值为一个包含题目内容和标准答案的字典。
试卷信息:可以使用字典存储,键为试卷号,值为一个字典,键为题目编号,值为题目分值。
学生信息:可以使用字典存储,键为学号,值为姓名。
答卷信息:可以使用列表存储,每个元素是一个字典,包含试卷号、学号和答案列表。
删除题目信息:可以使用列表或集合存储,方便快速查找。
处理流程
读取并解析输入:根据不同的前缀标识符(如#N:、#T:等)识别输入类型,然后将其解析并存储到相应数据结构中。
处理删除题目:遍历删除题目列表,从题目信息中移除对应的题目,并更新试卷信息中相关的题目分值为0。
处理试卷总分警示:检查每个试卷的总分是否为100分,如果不是则输出警示信息。
处理答卷信息:对于每份答卷,根据试卷号找到对应的试卷信息,然后逐题对比学生答案与标准答案,计算得分,并构建输出信息。
错误处理:在解析输入和处理答卷时,需要检查各种可能的错误情况,并按照要求输出错误信息。
实现要点
使用正则表达式来帮助解析输入,确保格式正确。
在处理删除题目时,需要同步更新所有引用了该题目的试卷信息。
在处理答卷时,要特别注意答案数量不足、题目被删除、题目不存在等情况的处理。
输出时,确保按照题目要求的格式准确无误地呈现信息。
心得体会
通过这次练习,我深刻理解到了数据结构选择的重要性,以及如何通过合理的数据结构设计来简化问题的解决。此外,错误处理也是编程中不可或缺的一部分,它能够提高程序的健壮性和用户体验。最后,实践证明,将复杂问题分解成多个小步骤逐一解决是一种非常有效的策略。以及题目中的样例全过并不能直接拿到全部的分数,以至于花费大量的时间对代码进行修改,说实话很大一部分在浪费时间,一些细节上的问题从网上学的内容根本起不到实际性的作用。

 if (input.matches("#N:(\\s*\\d+\\s*)#Q:(.*)#A:(.*)")) {
            int index1 = input.indexOf("#N:");
            int index2 = input.indexOf("#Q:");
            int index3 = input.indexOf("#A:");
            String num = input.substring(index1 + 3, index2).trim();
            int number = Integer.parseInt(num);
            String content = input.substring(index2 + 3, index3).trim();
            String standardAnswer = input.substring(index3 + 3, input.length()).trim();
            questions.put(number, new Question(number, content, standardAnswer, true));
        } else {
            System.out.println("wrong format:" + input);
        }
    }

我使用正则表达式处理了输入匹配逻辑,以及输入存在空格等问题。
但乱序输入,答案为空等情况写了很久也没有彻底改正。

踩坑心得
数据结构选择不当
问题:选择不合适的数据结构会导致性能问题和代码复杂性增加。
Map 用于快速查找和更新操作,例如 Map<Integer, Question> 用于存储题目。
List 用于有序集合,例如 List 用于存储答卷。
Set 用于去重和快速查找,例如 Set 用于存储被删除的题目编号。
类职责不明确
问题:类的职责过多或过少,导致代码难以维护和扩展。
单一职责原则:每个类只负责一个功能。例如,Question 只负责题目信息,Exam 负责试卷信息,GradingSystem 负责整体管理。
高内聚低耦合:类内部的方法和属性应紧密相关,不同类之间的依赖应尽量减少。
代码重复
问题:重复的代码会导致维护困难和潜在的错误。
提取公共方法:将重复的代码提取到公共方法中,例如 validateAnswer 方法可以放在 Question 类中。
继承和多态:利用继承和多态减少代码重复,例如不同类型的题目可以继承自一个基类。
改进建议

  1. 改进数据结构
    使用更高效的数据结构:
    TreeMap 替代 HashMap:如果需要按顺序访问题目或试卷,可以使用 TreeMap。
    ConcurrentHashMap 替代 HashMap:在多线程环境下,使用 ConcurrentHashMap 可以提高并发性能。
  2. 优化类设计
    引入接口:
    定义接口 IQuestion 和 IExam,使类更加灵活,便于扩展和替换实现。
public interface IQuestion {
    int getId();
    String getContent();
    String getAnswer();
    boolean isValid();
    void setValid(boolean valid);
    boolean validateAnswer(String answer);
}

public interface IExam {
    int getId();
    Map<Integer, Pair<IQuestion, Integer>> getQuestions();
    int getTotalScore();
    void addQuestion(IQuestion question, int score);
}

抽象类:
定义抽象类 AbstractQuestion 和 AbstractExam,提供默认实现。
3. 增强异常处理
自定义异常:
定义特定的异常类,以便更精确地处理错误情况。

public class GradingSystemException extends RuntimeException {
    public GradingSystemException(String message) {
        super(message);
    }
}

public class InvalidQuestionException extends GradingSystemException {
    public InvalidQuestionException(String message) {
        super(message);
    }
}

public class NonexistentEntityException extends GradingSystemException {
    public NonexistentEntityException(String message) {
        super(message);
    }
}

总结
通过这三次PTA作业,我对Java的面向对象编程有了更深的理解和实践。从最初的迷茫到现在的逐渐熟练,我学会了如何将复杂的问题拆分成多个模块,通过类和方法的设计来实现功能。同时,我也认识到了模块化设计和良好的错误处理机制的重要性。在未来的学习中,我将继续努力,不断提高自己的编程能力和解决问题的能力。了解了不同类型的类型的存储结构,Map 用于快速查找和更新操作,例如 Map<Integer, Question> 用于存储题目。List 用于有序集合,例如List 用于存储答卷。Set 用于去重和快速查找,例如 Set 用于存储被删除的题目编号。对正则表达式的使用不是非常熟练,每遇到一个新的问题都要去再搜索一遍。还有就是,事先设计是很有效果的因为真正写起来的时候,如果没有框架的辅助会写的很乱,甚至不知道从何处下手。

posted @ 2024-10-26 14:13  22207129-杨焱  阅读(12)  评论(0编辑  收藏  举报