Java大作业4-6次总结性BLOG

  • 前言

    • 本次BLOG由第4到6次的大作业答题判题程序- 4、家居强电电路模拟程序- 1和家居强电电路模拟程序 -2组成,其中答题判断程序-4由前三次迭代升级而来,涉及到填空题、单选题、多选题等多种题目的存储计算和判分逻辑。家居强电电路模拟程序为新的题目集,家居强电电路模拟程序1涉及到各个受控设备电压的计算,状态输出,以及开关状态的判断。家居强电电路模拟程序2由1迭代升级而来,在1的基础上增加了并联电路的逻辑,其设备状态的输出和判断的逻辑变得更为困难。这三次大作业的重点为多种子类的继承设计以及如何将具体逻辑抽象化为代码,本文将总结这三次大作业的知识点,以及难度,并分析每一道题目的核心内容和实现方法。
  • 答题判题程序-4

    • 题目分析

      • 这个题目要求我们设计并实现一个答题程序,处理和评估一个小型测试系统。该程序需要能够处理题目信息、试卷信息、答卷信息、学生信息和删除题目信息。以下是对该题目的分析和实现要点:

      • 功能需求分析

        1. 题目信息输入
          • 题目分为普通题目、选择题和填空题。
          • 每个题目都有编号、内容和标准答案。
          • 选择题可以有多个正确答案,用空格分隔。
          • 填空题的标准答案可以有多个正确选项,用“或”分隔。
        2. 试卷信息输入
          • 每张试卷有一个编号和多个题目及其分值。
          • 试卷的总分不一定为100分,但如果不为100分,需要输出警告。
        3. 学生信息输入
          • 学生信息包括学号和姓名。
        4. 答卷信息输入
          • 每个答卷对应一个学生和一张试卷。
          • 答卷中题目的顺序与试卷中的顺序对应。
          • 答案可能为空,需处理空答案的情况。
        5. 删除题目信息输入
          • 用于删除题目,删除后题目在试卷中计0分,并输出特定提示。
        6. 输出要求
          • 需要输出每道题的答题信息和判题结果。
          • 输出每份答卷的判分信息。
          • 如果试卷的题目引用了不存在的题目或被删除的题目,需要输出提示。
          • 如果格式错误,需要输出格式错误提示。
        7. 新增内容
          • 支持多选题和填空题的输入和评分。
          • 输出顺序按学号和试卷号排序。
          • 支持多张试卷的处理。
      • 实现要点

        1. 数据结构设计

          • 使用类来表示题目(普通题目、选择题、填空题)、试卷、学生、答卷。
          • 使用集合和映射来存储题目信息、试卷信息、学生信息和答卷信息。例如:
            private Map<Integer, Question> questions = new HashMap<>();
            private Map<Integer, TestPaper> testPapers = new HashMap<>();
            private Map<String, Student> students = new HashMap<>();
            private List<AnswerSheet> answerSheets = new ArrayList<>();
            private List<String> alerts = new ArrayList<>();
        2. 输入处理

          • 使用正则表达式解析输入字符串。
            Pattern questionPattern = Pattern.compile("#N:(\\d+) #Q:(.+?) #A:(.+)");
            Pattern multipleChoicePattern = Pattern.compile("#Z:(\\d+) #Q:(.+?) #A:(.+)");
            Pattern paperPattern = Pattern.compile("#T:(\\d+)((?: \\d+-\\d+)+)");
            Pattern studentPattern = Pattern.compile("#X:((?:\\w+ \\w+-?)+)");
            Pattern answerPattern = Pattern.compile("#S:(\\d+) (\\d+)((?: #A:\\d+-.+)+)");
            Pattern deletePattern = Pattern.compile("#D:N-(\\d+)");
            Pattern fillInTheBlankPattern = Pattern.compile("#K:(\\d+) #Q:(.+?) #A:(.+)");
          • 根据输入类型(题目、试卷、学生、答卷、删除)调用不同的处理函数。
          • 对输入的格式进行验证,发现错误时输出格式错误提示。
        3. 判题和评分逻辑

          • 对于普通题目,答案完全匹配给满分。
          • 对于选择题,答案完全匹配给满分,部分匹配给一半分,错误答案给0分。
          • 对于填空题,答案完全匹配给满分,部分匹配给一半分,错误答案给0分。
        4. 输出处理

          • 按照要求格式输出每道题的答题信息和判题结果。
          • 输出每份答卷的判分信息。
          • 处理删除题目和不存在题目的提示信息。
        5. 排序和输出

          • 在输出之前,对答卷信息按学号和试卷号排序。
          • 确保输出顺序符合要求。
    • 设计与分析

      • 整体逻辑

        1. 题目类及其子类
          • 首先使用正则表达式匹配不同格式的输入,根据匹配的结果,分别处理题目信息(普通题、多选题、填空题)、试卷信息、学生信息、答卷信息和删除题目信息,如果输入格式不符合要求,输出格式错误提示。
        2. 题目和试卷管理
          • 按照正则表达式分析输入内容并存入到相应的映射中,比如题目信息存储在 questions 映射中,允许通过题号快速访问,试卷信息存储在 testPapers 映射中,允许通过试卷号快速访问,学生信息存储在 students 映射中,允许通过学号快速访问。
        3. 答卷评判
          • 对于每份答卷,检查试卷和学生的有效性。本代码通过grade方法对答卷进行评分并处理不同类型的题目(普通题目,单选题,填空题),之后返回每道题目的答题信息和判题结果和学生的总分和每题得分。
        4. 输出
          • 最终的输出将按照学号和试卷号进行排序输出,并输出试卷总分,学生得分信息或警示,如果有题目删除和不存在的情况,也将会输出相应的提示信息。
      • 源码分析

        1. 题目类及其子类

          Question

          • 属性

            • id:题目的唯一标识符。
            • content:题目的具体内容。
            • correctAnswer:题目的正确答案。
            • deleted:标记题目是否已被删除,默认为 false
          • 方法

            • checkAnswer(String answer):比较传入的答案与正确答案是否相同。
            • delete():将 deleted 标志设置为 true,表示题目被删除。
            • isDeleted():返回 deleted 标志,检查题目是否被删除。
            • getContent():返回题目的内容。

          此类用于定义一个基本题目对象,提供了检查答案、删除题目等基本功能。

          MultipleChoiceQuestion

          • 继承:继承自 Question 类。

          • 方法

            • checkMultipleChoiceAnswer(String answer)
              • 将正确答案和用户答案都拆分为集合。
              • 检查用户答案中是否有错误答案(不在正确答案集合中),如果有,返回 "false"
              • 检查用户答案是否与正确答案数量一致,如果一致,返回 "true"
              • 如果用户答案部分正确(没有错误答案,但数量不匹配),返回 "partially correct"

          此类用于处理多选题的答案判定,支持完全正确、部分正确和错误的判断。

          FillInTheBlankQuestion

          • 继承:继承自 Question 类。

          • 方法

            • checkFillInTheBlankAnswer(String answer)
              • 首先检查用户答案是否与正确答案完全匹配。
              • 将正确答案和用户答案拆分为集合,检查无序的完全匹配。
              • 检查用户答案是否包含任一正确答案的部分内容。
              • 返回 "true""partially correct""false"

          此类用于处理填空题的答案判定,支持无序匹配和部分正确判断。

        2. 试卷类

          TestPaper

          • 属性

            • id:试卷的唯一标识符。
            • questionIds:试卷中题目的编号列表。
            • scores:每个题目的分值列表。
            • totalScore:试卷的总分。
          • 方法

            • addQuestion(int questionId, int score):向试卷中添加题目及其分值,并更新总分。
            • isValid():检查试卷的总分是否为100分。
            • getQuestionIds():返回试卷中题目的编号列表。
            • getScore(int index):返回指定题目的分值。

          此类用于定义一个试卷对象,管理试卷中的题目和分值。

        3. 学生类

          Student

          • 属性
            • id:学生的学号。
            • name:学生的姓名。

          此类用于存储学生的基本信息。

        4. 答卷类

          AnswerSheet

          • 属性

            • paperId:答卷对应的试卷编号。
            • studentId:答卷对应的学生学号。
            • answers:存储题目编号和学生答案的映射。
            • scores:存储每个题目的得分。
            • totalScore:答卷的总分。
          • 方法

            • addAnswer(int questionNum, String answer):添加学生对某题的答案。
            • grade(TestPaper testPaper, Map<Integer, Question> questions)
              • 迭代试卷中的每个题目,通过题目编号从 questions 映射中获取题目对象。
              • 检查答案是否为空、题目是否存在或已被删除。
              • 根据题目类型调用相应的判定方法,计算得分。
              • 更新每题得分和总分。
            • printStudentScore(Student student):输出学生的学号、姓名、每题得分及总分。

          此类用于处理答卷的评分和结果输出。

        5. 输入处理类

          InputHandler

          • 属性

            • scanner:用于读取输入。
            • questions:存储所有题目的映射。
            • testPapers:存储所有试卷的映射。
            • students:存储所有学生的映射。
            • answerSheets:存储所有答卷的列表。
            • alerts:存储警示信息的列表。
          • 方法

            • handleInput()
              • 使用正则表达式解析不同格式的输入。
              • 根据输入内容创建题目、试卷、学生和答卷对象,并存储在相应的数据结构中。
              • 如果试卷总分不是100分,添加警示信息。
              • 处理题目删除指令。
            • printResults()
              • 输出警示信息。
              • 按学号和试卷号排序答卷。
              • 对每份答卷进行评分并输出结果。

          此类负责处理所有输入和输出,管理程序的主要逻辑流程。

        6. 主类

          Main

          • 方法
            • main(String[] args)
              • 创建 InputHandler 对象。
              • 调用 handleInput() 方法处理输入。
              • 调用 printResults() 方法输出结果。

          此类是程序的入口,负责启动整个程序的执行。

其类图参考如下:

时序图

  • 踩坑心得

    问题描述

    1. 乱序输入问题

      • 在程序中,题目、试卷、学生和答卷信息可以以任意顺序输入。这意味着在处理答卷时,可能会遇到试卷或题目尚未输入的情况,导致程序无法正确评分。
    2. 判题半对问题

      • 在处理多选题和填空题的判定时,需要支持部分正确的判断。然而,部分正确的判定逻辑较为复杂,容易出现误判或漏判的情况。例如,多选题中用户的答案可能包含正确和错误的选项,如何准确地判断部分正确是一个难点。

    解决方法

    1. 乱序输入的解决方法

      • 使用 Map 数据结构

        • InputHandler 类中,通过 Map<Integer, Question> questionsMap<Integer, TestPaper> testPapersMap<String, Student> students 来存储题目、试卷和学生的信息。这种方式允许我们在需要时快速检索数据。
        • 例如,在 AnswerSheet 类的 grade 方法中,我们通过 questions.get(questionId) 来获取题目信息,并通过 testPapers.get(sheet.paperId) 来获取试卷信息。
      • 检查存在性

        • InputHandlerprintResults 方法中,我们首先检查试卷和学生是否存在:
          TestPaper paper = testPapers.get(sheet.paperId);
          if (paper == null) {
              System.out.println("The test paper number does not exist");
              continue;
          }
          Student student = students.get(sheet.studentId);
          if (student == null) {
              System.out.println(sheet.studentId + " not found");
              continue;
          }
          
    2. 判题半对问题的解决方法

      • 多选题判定

        • MultipleChoiceQuestion 类中,通过 checkMultipleChoiceAnswer 方法来处理答案的判定。我们使用 Set 来存储正确答案和用户答案,以便进行集合操作:
          String[] correctAnswers = correctAnswer.split(" ");
          Set<String> userAnswers = new HashSet<>(Arrays.asList(answer.split(" ")));
          
          boolean hasError = userAnswers.stream().anyMatch(ans -> !Arrays.asList(correctAnswers).contains(ans));
          
          if (hasError) {
              return "false";
          }
          
          if (userAnswers.size() == correctAnswers.length) {
              return "true";
          } else {
              return "partially correct";
          }
          
      • 填空题判定

        • FillInTheBlankQuestion 类中,通过 checkFillInTheBlankAnswer 方法来处理填空题的判定。我们使用 Set 来比较用户答案和正确答案的不同组合:
          String[] correctAnswerOptions = correctAnswer.split("或");
          String[] answerOptions = answer.split("或");
          
          Set<String> correctAnswerSet = new HashSet<>(Arrays.asList(correctAnswerOptions));
          Set<String> answerSet = new HashSet<>(Arrays.asList(answerOptions));
          
          if (answerSet.equals(correctAnswerSet)) {
              return "true";
          }
          
          for (String option : correctAnswerOptions) {
              if (answer.trim().equals(option.trim())) {
                  return "partially correct";
              }
          }
          
          if (answer.isEmpty()) {
              return "false";
          }
          
          return "false";
          
  • 改进与建议

    1. 代码重构与模块化设计

      • 重构复杂逻辑:将复杂的判题逻辑和数据处理步骤拆分为更小的、独立的方法。每个方法应只负责一个具体的任务,比如处理特定类型的题目(选择题、填空题等)的判定。这样可以提高代码的可读性和可维护性。
      • 模块化设计:将程序中的不同功能模块(如输入处理、判题、成绩计算等)进行模块化设计。使用接口和抽象类来定义模块之间的交互,使得每个模块可以独立开发和测试。
    2. 增强输入验证和错误处理

      • 输入验证:在数据输入阶段,增加严格的验证机制。例如,确保题目和答案格式正确,学生信息完整。可以通过正则表达式或预定义规则来验证输入数据的合法性。
      • 详细错误处理:在程序中提供详细的错误处理机制。当出现输入错误或数据不一致时,给出明确的错误信息和建议。例如,提示用户具体哪个字段有问题,以及如何修正。
    3. 优化判题逻辑的性能和灵活性

      • 性能优化:对于大规模数据集,优化数据结构和算法以提高判题效率。例如,使用哈希表来快速查找题目和答案,减少不必要的循环和比较操作。
      • 灵活性提升:允许教师自定义判题规则和评分标准。例如,提供配置文件或用户界面,让用户可以设置不同题型的评分细则和部分得分标准。这不仅提高了系统的灵活性,也能更好地满足不同考试场景的需求。
  • 家居强电电路模拟程序-1

    • 题目分析

      • 本题要求设计一个智能家居强电电路模拟系统。该系统需要模拟控制设备和受控设备的行为,并根据输入信息输出设备的状态。以下是对题目的详细分析和实现要点:

      功能需求分析

      1. 控制设备模拟

        • 开关:具有两种状态(0和1)。当状态为0时,输出电位为0;当状态为1时,输出电位等于输入电位。
        • 分档调速器:模拟4档调速器,输出电位为输入电压的0、0.3、0.6、0.9倍。
        • 连续调速器:输出电位为档位参数(范围为0.00-1.00)乘以输入电压。
      2. 受控设备模拟

        • 灯具
          • 白炽灯:亮度与电位差成正比,最大亮度为220V对应200lux。
          • 日光灯:亮度为180lux,当电位差不为0时亮。
        • 吊扇:工作电压区间为80V-150V,转速与电压差成正比,最大转速为360转/分钟。
      3. 输入信息

        • 设备信息:用标识符表示不同设备,编号用于区分不同实例。
        • 连接信息:使用方括号表示连接在一起的设备引脚。
        • 控制设备调节信息:用于改变设备状态或档位。
        • 电源接地标识:VCC为220V,GND为0V。

      实现要点

      1. 数据结构设计

        • 使用类来表示不同的设备(开关、调速器、灯具、吊扇)。
        • 每个设备类包含其特定的属性和方法,如状态、档位、输入输出引脚等。
      2. 输入处理

        • 解析输入信息,包括设备信息、连接信息和调节信息。
        • 使用正则表达式或字符串操作解析输入格式。
      3. 电路模拟与计算

        • 根据连接信息构建电路,计算各设备的输入输出电压。
        • 实现设备的行为逻辑,模拟其状态变化和输出。
      4. 输出处理

        • 按要求格式输出设备的状态或参数。
        • 确保输出顺序为开关、分档调速器、连续调速器、白炽灯、日光灯、吊扇。

      设计与分析

      1. 设备类设计

        • 开关类:包含状态属性,并实现状态切换和输出电压计算。
        • 调速器类:分为分档和连续调速器,包含档位属性和输出电压计算方法。
        • 灯具类:实现亮度计算方法,考虑电位差与亮度的关系。
        • 吊扇类:实现转速计算方法,考虑电压差与转速的关系。
      2. 电路连接与计算

        • 根据输入的连接信息,模拟电路连接,计算各设备的输入输出电压。
        • 使用图结构或邻接表表示电路连接关系,便于计算电压传播。
      3. 状态更新与输出

        • 根据调节信息更新设备状态或档位。
        • 使用格式化字符串输出设备的当前状态或参数值。
    • 设计与分析

      • 整体逻辑

        1. 设备类及其子类

          • 代码中定义了多个设备类,每个类代表一种设备类型,如开关、调速器、灯具和风扇等。
          • 每个设备类都实现了 Device 抽象类,定义了更新状态和获取状态的方法。
          • 控制设备类(如 SwitchSpeedControllerContinuousSpeedController)实现了控制逻辑,通过输入电压和设备状态计算输出电压。
          • 受控设备类(如 LightFan)根据输入电压更新自身状态,如亮度或转速。
        2. 电路管理

          • SmartHomeCircuit 类负责管理整个电路系统,包括设备的存储和连接。
          • 使用 Map 存储设备,允许通过设备标识符快速访问设备实例。
          • 连接请求存储在一个列表中,待所有输入处理完毕后统一处理连接。
          • processConnections() 方法遍历连接请求,根据连接关系更新设备的输入电压。
        3. 命令解析

          • CommandParser 类负责解析输入命令,识别并处理连接命令和控制命令。
          • parseConnectionCommand() 方法解析连接命令,创建设备实例并记录连接关系。
          • parseControlCommand() 方法解析控制命令,调整设备状态(如开关状态切换、调速器档位调整)。
        4. 输入处理

          • 主程序通过 Scanner 从标准输入读取命令。
          • 根据命令格式(连接命令或控制命令),调用 CommandParser 进行解析。
          • 连接命令用方括号表示,控制命令用 # 开头。
        5. 状态更新与输出

          • processConnections() 方法在所有输入命令处理完毕后执行,更新设备的连接状态。
          • displayStates() 方法输出所有设备的状态,按照设备类型和编号排序输出。
          • 使用 TreeMap 对设备进行分类和排序,确保输出顺序符合要求(开关、分档调速器、连续调速器、白炽灯、日光灯、吊扇)。
      • 源码分析

        1. 设备类及其子类

          Device

          • 属性

            • 抽象类,没有具体属性。
          • 方法

            • updateState(double inputVoltage):抽象方法,用于更新设备状态。
            • getStatus():抽象方法,用于获取设备的当前状态。

          此类是所有设备的基类,定义了设备的基本接口。

          VCC

          • 继承:继承自 Device 类。

          • 属性

            • inputVoltage:固定为220V,表示电源电压。
          • 方法

            • updateState(double inputVoltage):不做任何操作。
            • getStatus():返回空字符串。

          此类用于表示电源设备,提供固定的电压输出。

          Ground

          • 继承:继承自 Device 类。

          • 属性

            • outputVoltage:固定为0V,表示接地电压。
          • 方法

            • updateState(double inputVoltage):不做任何操作。
            • getStatus():返回空字符串。

          此类用于表示接地设备,输出电压为0。

          ControlDevice

          • 继承:继承自 Device 类。

          • 属性

            • inputVoltage:输入电压。
            • outputVoltage:输出电压。
          • 方法

            • control():抽象方法,用于控制设备输出。
            • getOutputVoltage():返回设备的输出电压。

          此类用于表示具有控制功能的设备,是控制设备的抽象基类。

          Switch

          • 继承:继承自 ControlDevice 类。

          • 属性

            • isOn:布尔值,表示开关状态。
          • 方法

            • toggle():切换开关状态。
            • control():根据开关状态设置输出电压。
            • updateState(double inputVoltage):更新输入电压并调用 control()
            • getStatus():返回开关状态。

          此类用于表示开关设备,控制电压的通断。

          SpeedController

          • 继承:继承自 ControlDevice 类。

          • 属性

            • level:整数,表示调速档位。
          • 方法

            • upLevel():增加档位。
            • downLevel():减少档位。
            • getLevelFactor():根据档位返回相应的因子。
            • control():根据档位因子调整输出电压。
            • updateState(double inputVoltage):更新输入电压并调用 control()
            • getStatus():返回当前档位。

          此类用于表示档位调速器,通过档位控制输出电压。

          ContinuousSpeedController

          • 继承:继承自 ControlDevice 类。

          • 属性

            • speedFactor:双精度浮点数,表示调速因子。
          • 方法

            • setSpeedFactor(double factor):设置并限制调速因子在0到1之间,调用 control()
            • control():根据调速因子调整输出电压。
            • updateState(double inputVoltage):更新输入电压并调用 control()
            • getStatus():返回调速因子。

          此类用于表示连续调速器,通过调速因子控制输出电压。

          ControlledDevice

          • 继承:继承自 Device 类。

          • 属性

            • inputVoltage:输入电压。
            • outputVoltage:输出电压。
          • 方法

            • updateState(double inputVoltage):抽象方法,用于更新设备状态。

          此类用于表示受控设备,是受控设备的抽象基类。

          Light

          • 继承:继承自 ControlledDevice 类。

          • 属性

            • brightness:整数,表示灯光亮度。
          • 方法

            • updateState(double inputVoltage):抽象方法,由子类实现。
            • getStatus():返回亮度。

          此类用于表示灯具设备,控制亮度。

          Fan

          • 继承:继承自 ControlledDevice 类。

          • 属性

            • speed:整数,表示风扇速度。
          • 方法

            • getSpeed():返回风扇速度。
            • setSpeed(int speed):设置风扇速度。
            • updateState(double inputVoltage):根据输入电压更新风扇速度。
            • getStatus():返回速度。

          此类用于表示风扇设备,控制转速。

          IncandescentLight

          • 继承:继承自 Light 类。

          • 方法

            • updateState(double inputVoltage):根据输入电压更新亮度。

          此类用于表示白炽灯,控制亮度。

          FluorescentLight

          • 继承:继承自 Light 类。

          • 方法

            • updateState(double inputVoltage):根据输入电压设置亮度。

          此类用于表示日光灯,控制亮度。

          2. 电路管理

          SmartHomeCircuit

          • 属性

            • devices:存储设备的映射,键为设备标识符。
            • connectionRequests:存储连接请求的列表。
          • 方法

            • getDevice(String deviceId):获取设备实例。
            • addDevice(String deviceName, Device device):添加设备。
            • addConnectionRequest(String deviceId1, String deviceId2):添加连接请求。
            • processConnections():处理连接请求,更新设备状态。
            • connectDevices(String deviceId1, String deviceId2):根据连接关系更新设备状态。
            • displayStates():输出设备状态。

          此类用于管理智能家居电路,处理设备的连接和状态更新。

          3. 命令解析

          CommandParser

          • 属性

            • circuitSmartHomeCircuit 的实例。
          • 方法

            • parseConnectionCommand(String input):解析连接命令,创建设备并记录连接。
            • parseControlCommand(String input):解析控制命令,调整设备状态。
            • createDevice(String deviceType):根据设备类型创建设备实例。

          此类用于解析输入命令,配置电路连接和设备状态。

          4. 主类

          Main

          • 方法
            • main(String[] args)
              • 创建 SmartHomeCircuitCommandParser 实例。
              • 从标准输入读取命令,调用相应方法解析。
              • 处理连接并输出设备状态。

          参考类图:

          • 时序图

  • 踩坑心得

    问题描述

    1. 设备连接的复杂性

      • 在智能家居电路系统中,设备的连接关系可能非常复杂,尤其是在处理多个设备之间的连接时。由于输入命令可能是乱序的,设备之间的连接需要在所有设备创建之后才能正确处理。这导致在解析和处理连接命令时可能会遇到设备尚未创建的情况。
    2. 设备状态更新的挑战

      • 设备状态的更新依赖于输入电压和设备的当前状态。例如,开关的开闭状态会影响下游设备的电压,调速器的档位或因子会影响输出电压。这种状态更新需要确保在设备连接关系处理完毕后进行,以避免状态不一致的问题。

    解决方法

    1. 设备连接的解决方法

      • 使用 Map 数据结构

        • SmartHomeCircuit 类中,通过 Map<String, Device> devices 来存储所有设备的信息。这种方式允许我们在需要时快速检索设备。连接请求存储在 List<String[]> connectionRequests 中,待所有设备创建完毕后统一处理连接。
        • 例如,在 processConnections 方法中,我们遍历 connectionRequests 列表,通过 getDevice(deviceId) 方法获取设备实例,确保设备存在后再进行连接:
          for (String[] request : connectionRequests) {
              Device device1 = getDevice(request[0]);
              Device device2 = getDevice(request[1]);
              if (device1 != null && device2 != null) {
                  connectDevices(request[0], request[1]);
              }
          }
          
      • 延迟连接处理

        • CommandParser 类中,解析连接命令时先记录连接请求,而不是立即处理连接。这确保了即使输入顺序混乱,也能在所有设备创建后正确建立连接关系。
    2. 设备状态更新的解决方法

      • 统一状态更新机制

        • SmartHomeCircuit 类的 processConnections 方法中,连接设备后立即更新设备的输入电压,并调用 updateState 方法以确保设备状态与连接关系一致。
        • 例如,开关设备在连接后会根据其状态设置输出电压,影响下游设备的状态更新:
          if (device1 instanceof ControlDevice && device2 instanceof ControlledDevice) {
              ((ControlledDevice) device2).updateState(((ControlDevice) device1).getOutputVoltage());
          }
          
      • 设备状态输出

        • displayStates 方法中,通过遍历 devices 映射,按照设备类型和编号排序输出状态。这确保了输出结果的可读性和一致性:
          devices.entrySet().stream()
              .sorted(Map.Entry.comparingByKey())
              .forEach(entry -> System.out.println(entry.getValue().getStatus()));
          
  • 改进与建议

    1. 改进设备连接的处理逻辑

      • 建议使用事件驱动机制:引入事件驱动的机制来处理设备连接和状态更新。可以在设备创建时注册一个事件,当所有设备创建完成并准备好处理连接时,触发一个事件来批量处理所有连接请求。这不仅可以使代码逻辑更清晰,还可以避免在处理连接时设备未创建的问题。
      • 实时连接反馈:在添加连接请求时,提供实时反馈机制。如果请求的设备尚未创建,可以立即记录警告信息,提示用户设备缺失。这可以帮助用户在输入阶段就发现并纠正错误。
    2. 优化设备状态更新的效率

      • 引入状态缓存:为了减少重复计算和提高效率,可以为设备状态引入缓存机制。在设备的状态更新方法中,只有当输入电压或控制参数发生变化时才更新状态。这可以减少不必要的计算,尤其是在复杂的电路中具有显著的性能提升。
      • 批量更新机制:对于涉及多个设备的状态更新,可以考虑引入批量更新机制。在完成所有连接处理后,统一触发所有设备的状态更新,而不是在每次连接时立即更新。这可以减少状态更新的次数,提高整体系统的响应速度。
  • 家居强电电路模拟程序-2

    • 题目分析

      本题要求设计一个智能家居强电电路模拟系统,旨在通过模拟控制设备和受控设备的行为,实现对智能家居电路的全面模拟和控制。相较于“家居强电电路模拟程序-1”,本次题目增加了如下功能和要求:

      1. 控制设备的拓展

        • 新增了分档调速器和连续调速器的模拟。分档调速器具有多个档位,每个档位输出不同的电压比例;连续调速器则通过档位参数按比例输出电压。这些设备的引入使得电路模拟更加复杂和逼真。
      2. 受控设备类型的增加

        • 本次迭代中增加了白炽灯、日光灯、吊扇和落地扇的模拟。每种设备都有特定的工作状态和性能参数(如亮度和转速),这些参数根据电压差变化。白炽灯和日光灯的亮度特性不同,吊扇和落地扇的转速特性也各异,这些细节丰富了电路模拟的内容。
      3. 电路连接和控制信息的复杂化

        • 本次迭代引入了串联和并联电路的概念,要求处理更复杂的连接信息。电路的信息输入包括串联电路和并联电路的定义,连接信息需要按照电路从电源到接地的顺序输入。此外,控制设备的调节信息格式也有所增加,支持对开关、分档调速器和连续调速器进行调节。

      功能需求分析

      1. 设备信息输入

        • 每个设备通过标识符和编号进行标识,并通过引脚连接。设备信息直接包含在连接信息中,不单独输入。
      2. 电路连接信息输入

        • 连接信息以方括号表示,支持设备的串联和并联接入。串联电路和并联电路有各自的定义格式,要求按顺序输入。
      3. 控制设备调节信息输入

        • 支持对开关状态的切换、分档调速器的档位调整和连续调速器档位参数的设置。
      4. 电源接地标识

        • 电源(VCC)和接地(GND)的电压分别为220V和0V,未接线的引脚默认接地。
      5. 输出设备状态

        • 按开关、分档调速器、连续调速器、白炽灯、日光灯、吊扇、落地扇的顺序输出设备的状态或参数,确保输出格式和顺序符合要求。

      实现要点

      1. 数据结构设计

        • 使用类和数据结构存储设备信息、连接信息和调节信息。需要设计合理的类层次结构来表示不同类型的设备及其特性。
      2. 输入处理

        • 解析输入字符串,处理设备和连接信息,确保输入格式正确并能正确解析复杂的电路结构。
      3. 设备状态更新和电路模拟

        • 根据连接关系和控制信息,模拟设备的工作状态和电路行为。确保设备状态的更新逻辑正确,尤其是在复杂的串联和并联电路中。
      4. 输出处理

        • 按照要求格式输出设备的状态或参数,确保输出结果的准确性和可读性。
    • 设计与分析

      • 整体逻辑

        设备类及其子类:

        • 设备抽象类

          • 代码中定义了一个抽象类 Device,它为所有设备定义了基本接口,包括更新状态、获取状态和获取电阻的方法。
          • 各种设备类(如开关、调速器、灯具和风扇)继承自 Device,并实现了这些接口。
        • 控制设备类

          • 控制设备类(如 SwitchSpeedControllerContinuousSpeedController)继承自 ControlDevice,实现了特定的控制逻辑。
          • 每个控制设备根据输入电压和自身状态(如开关状态或调速档位)计算输出电压。
          • 控制设备可以通过特定的方法(如切换开关、调整档位)改变其状态。
        • 受控设备类

          • 受控设备类(如 LightFan)继承自 ControlledDevice,根据输入电压更新自身状态,如亮度或转速。
          • 各种灯具和风扇类实现了特定的状态更新逻辑,以模拟不同的物理特性。

        电路管理:

        • SmartHomeCircuit 类

          • 负责管理整个电路系统,包括设备的存储、连接和状态更新。
          • 使用 Map 存储设备,以设备标识符为键,允许快速访问设备实例。
          • 连接请求存储在一个列表中,待所有输入处理完毕后统一处理连接。
        • 连接处理

          • processConnections() 方法遍历连接请求,根据连接关系更新设备的输入电压。
          • 并联电路和串联电路的电阻计算分别由 ParallelCircuitSeriesCircuit 类处理。
          • 通过计算总电阻,合理分配电压,模拟真实电路中的电压分配。

        命令解析:

        • CommandParser 类
          • 负责解析输入命令,识别并处理连接命令和控制命令。
          • parseSeriesCircuitCommand()parseParallelCircuitCommand() 方法解析串联和并联电路的命令,创建设备实例并记录连接关系。
          • parseControlCommand() 方法解析控制命令,调整设备状态(如开关状态切换、调速器档位调整)。

        输入处理:

        • 主程序输入
          • 主程序通过 Scanner 从标准输入读取命令。
          • 根据命令格式(连接命令或控制命令),调用 CommandParser 进行解析。
          • 串联电路命令以 #T 开头,并联电路命令以 #M 开头,控制命令以 # 开头。

        状态更新与输出:

        • 状态更新

          • processConnections() 方法在所有输入命令处理完毕后执行,更新设备的连接状态。
          • 设备的状态根据电路连接和输入电压进行更新。
        • 状态输出

          • displayStates() 方法输出所有设备的状态,按照设备类型和编号排序输出。
          • 使用 TreeMap 对设备进行分类和排序,确保输出顺序符合要求(如开关、分档调速器、连续调速器、白炽灯、日光灯、吊扇、落地扇)。
      • 源码分析

        设备类及其子类

        Device
        • 属性

          • 这是一个抽象类,没有具体属性,但定义了所有设备必须实现的接口。
        • 方法

          • updateState(double inputVoltage):更新设备的状态,基于输入电压。
          • getStatus():获取设备的当前状态,以字符串形式返回。
          • getResistance():返回设备的电阻值。

          Device 类用于定义所有设备的基本接口,确保所有设备类都有统一的行为。

        ControlDevice
        • 继承:继承自 Device 类。

        • 属性

          • inputVoltage:设备的输入电压。
          • outputVoltage:设备的输出电压。
        • 方法

          • control():抽象方法,定义控制设备的核心逻辑。
          • getOutputVoltage():返回设备的输出电压。

          ControlDevice 类为控制设备提供了输入和输出电压的基础结构。

        Switch
        • 继承:继承自 ControlDevice 类。

        • 属性

          • isOn:表示开关的状态,初始为关闭。
        • 方法

          • toggle():切换开关状态。
          • control():根据开关状态更新输出电压。
          • updateState(double inputVoltage):更新输入电压并调用 control() 方法。

          Switch 类实现了开关设备的逻辑,可以通过 toggle() 方法改变状态。

        SpeedController
        • 继承:继承自 ControlDevice 类。

        • 属性

          • level:当前档位,初始为0。
        • 方法

          • upLevel()downLevel():调整档位。
          • getLevelFactor():返回当前档位对应的电压因子。
          • control():根据档位因子计算输出电压。
          • updateState(double inputVoltage):更新输入电压并调用 control() 方法。

          SpeedController 类实现了分档调速器的逻辑,通过档位调整输出电压。

        电路管理

        SmartHomeCircuit
        • 属性

          • devices:存储所有设备的映射。
          • connectionRequests:存储连接请求的列表。
          • parallelCircuitseriesCircuit:用于处理并联和串联电路。
          • simulationParaller:用于模拟并联电路的电压分配。
        • 方法

          • addDevice(String deviceName, Device device):添加设备到电路。
          • processConnections(...):处理连接请求,更新设备状态。
          • calculateResistance(...):计算电路的总电阻。
          • displayStates():输出所有设备的状态。

          SmartHomeCircuit 类负责管理整个电路系统,包括设备的添加、连接和状态更新。

        命令解析

        CommandParser
        • 属性

          • circuit:引用 SmartHomeCircuit 实例。
          • seriesCircuitsparallelCircuits:存储串联和并联电路的结构。
        • 方法

          • parseSeriesCircuitCommand(String input):解析串联电路命令。
          • parseParallelCircuitCommand(String input):解析并联电路命令。
          • parseControlCommand(String input):解析控制命令,调整设备状态。

          CommandParser 类负责解析输入命令,识别并处理电路结构和设备控制指令。

        主类

        Main
        • 方法

          • main(String[] args)
            • 创建 SmartHomeCircuitCommandParser 对象。
            • 从标准输入读取命令并解析。
            • 处理连接并更新设备状态。
            • 输出设备状态。

          Main 类是程序的入口,负责初始化系统并协调各个组件的工作。通过解析用户输入,模拟智能家居电路的配置和操作。
          以下是参考类图:

      • 时序图

  • 踩坑心得

    问题描述

    1. 并联电路逻辑设计的复杂性

      • 在智能家居电路系统中,并联电路的设计尤为复杂,因为并联电路中各设备的电压相等,但电流分配不同。处理并联电路的逻辑需要确保所有设备都能正确接收到相同的电压,而这在解析和实现时会遇到挑战,尤其是在设备连接和电压计算过程中。
    2. 并联电路中设备电压计算的挑战

      • 并联电路中,每个设备的电压应与总电压相等,但由于设备的电阻和状态不同,如何在程序中准确计算和分配电压是一个难点。错误的电压计算可能导致设备状态更新不正确,进而影响整个电路的模拟结果。

    解决方法

    1. 并联电路逻辑设计的解决方法

      • 使用专门的电路类

        • 在系统中设计 ParallelCircuit 类来专门处理并联电路的逻辑。通过这个类,可以将并联电路的设备视为一个整体,统一管理其电压分配。
        • 例如,在 ParallelCircuit 类中,定义一个方法 calculateVoltageDistribution() 来确保所有设备接收到相同的电压:
          public void calculateVoltageDistribution(double totalVoltage) {
              for (Device device : devices) {
                  device.updateState(totalVoltage);
              }
          }
          
      • 连接请求的延迟处理

        • CommandParser 类中,解析并联电路的命令时,先将连接请求存储起来,而不是立即处理。这种方式确保在所有设备创建完毕后,能够正确地建立并联电路的连接关系。
    2. 并联电路中设备电压计算的解决方法

      • 统一电压更新机制

        • SmartHomeCircuit 类中,设计一个统一的机制来更新并联电路中每个设备的电压。在 processConnections 方法中,识别并联电路后,调用 ParallelCircuit.calculateVoltageDistribution() 方法分配电压。
        • 例如:
          if (isParallelCircuit(connection)) {
              parallelCircuit.calculateVoltageDistribution(totalVoltage);
          }
          
      • 确保电压一致性

        • displayStates 方法中,输出设备状态时验证电压的一致性,确保并联电路中的所有设备电压相同。这可以通过在遍历设备状态时检查电压是否与预期一致来实现:
          devices.entrySet().stream()
              .filter(entry -> entry.getValue() instanceof ParallelDevice)
              .forEach(entry -> {
                  double expectedVoltage = totalVoltage; // 假设并联电路总电压
                  assert entry.getValue().getVoltage() == expectedVoltage;
                  System.out.println(entry.getValue().getStatus());
              });
          
  • 改进与建议

    1. 使用单元测试覆盖关键逻辑

      • 为电路系统的关键部分编写单元测试,特别是设备连接、状态更新和电压计算等核心逻辑。通过使用测试驱动开发(TDD)的方法,可以确保在代码改动或重构时不会引入新的错误。使用测试框架(如 JUnit)编写自动化测试用例,以验证每个模块的功能和边界条件。
    2. 优化数据结构选择

      • 考虑使用更高效的数据结构来管理设备和连接。例如,可以使用 HashMap 来存储设备以便快速检索,同时使用 Graph 数据结构来表示设备之间的连接关系。这不仅提高了连接和状态更新的效率,还能更方便地实现复杂的电路拓扑操作(如循环检测和路径查找)。
  • 总结

    在本阶段的学习中,通过设计和实现复杂的答题程序和智能家居强电电路模拟系统,我学到了许多关于软件设计、数据结构、算法实现以及系统模拟的知识。

    首先,在答题程序的设计中,我学会了如何处理多种输入格式的信息,并将其解析为程序可处理的数据结构。这包括处理题目信息、试卷信息、学生信息、答卷信息和删除题目信息等。尤其是在新增选择题和填空题的情况下,我掌握了如何实现多种题型的判分逻辑,以及如何根据不同的题型和答案情况(如部分正确、多选题的部分匹配等)进行灵活的评分。

    在智能家居强电电路模拟系统中,我深入理解了如何模拟和控制各种设备(如开关、调速器、灯具、风扇等),并通过电路连接信息来模拟实际电路的行为。这让我对物联网设备的模拟有了更深刻的理解,尤其是在处理复杂的电路连接和设备状态更新时,如何有效地组织代码和数据结构。

    然而,还有一些领域需要进一步学习和研究。首先是更深入的设计模式和架构知识,以便在处理更大规模和复杂度的系统时,能够更好地组织代码和模块。其次是优化算法和数据结构的使用,尤其是在处理大量输入数据和复杂逻辑时,如何提高程序的性能和响应速度。此外,如何更好地进行单元测试和系统测试,以确保代码的准确性和稳定性,也是一个需要深入学习的领域。

    对于课程的改进建议,可以增加更多的实际项目和案例分析,让学生在真实的环境中应用所学的知识。同时,增加对现代软件开发工具和技术的介绍,如版本控制、自动化测试和持续集成等,也将对学生的未来发展大有裨益。通过这些改进,课程将更具实用性和前瞻性,帮助学生更好地应对未来的技术挑战。

posted @ 2024-11-23 20:17  千世绪川  阅读(60)  评论(0)    收藏  举报