题目集4~6的总结性Blog
一.前言
在过去三次大作业程序开发的学习和实践过程中,模拟现实场景是提高设计能力和解决问题能力的绝佳途径。无论是一个复杂的考试判题系统,还是一个家居强电电路的模拟程序,都要求我们用计算机语言实现对多种逻辑和规则的精准模拟。这些程序不仅需要我们对面向对象编程、数据结构、算法有较深的理解,还要求我们具备系统性地处理多种输入、动态关联关系和复杂条件判断的能力。
在家居强电电路模拟程序-1中,我们构建了一个简单的电路模拟器,通过解析设备状态、设备控制和电路连接来模拟现实中的电流流动和设备开关状态。而在考试判题系统中,我们设计了一个复杂的评分逻辑,既要处理多样化题型(普通题、多选题、填空题),又要实现对异常输入、特殊评分规则的精准处理。这些项目既是对程序开发能力的锻炼,也是对思维严谨性和逻辑清晰度的深刻考验。
二.设计与分析
1.家居强电电路模拟程序-1
(1)难度分析
- 业务逻辑复杂性
题目要求模拟多种设备(开关、调速器、灯具、风扇)的行为,不同设备有不同的控制逻辑和状态更新规则。这对逻辑设计和状态管理提出了较高要求。
设备之间的连接关系复杂,需要解析连接信息并按照电路顺序计算电压分布、设备输出等参数。 - 面向对象设计复杂性
题目建议设计多个类(设备类、控制设备类、受控设备类等)并使用继承和多态的特性组织设备的行为。
类与类之间的关系(如设备连接关系、电路类的组织方式)需要用合理的对象模型表示,可能涉及组合模式或其他设计模式。 - 输入解析与输出格式
输入信息包含设备连接、调节指令等,格式较为固定但复杂,解析时需要对字符串处理有较强的掌握。
输出要求格式化输出各设备状态,这需要严格按照题目描述完成。 - 算法与数学计算
题目涉及多个设备状态的计算公式(如灯具亮度计算、风扇转速计算),同时要求对小数截尾并精确到整数,需要正确理解和实现公式。
串联电路的电压分配需要在连接关系的基础上正确建模和计算。 - 边界条件处理
需要处理多种边界情况,例如输入无效、设备编号不连续或未按规定顺序连接、设备初始状态为零等。
要确保所有控制设备和受控设备的状态更新逻辑都符合题目约束
(2)知识点分析
-
面向对象编程
类的设计与继承:设备的公共属性和方法可以提取到基类,开关、调速器等设备可以作为子类扩展。
多态:通过多态实现不同设备行为的统一接口调用,便于设备管理和状态更新。
封装与组合:电路连接信息的解析和处理可以封装在单独的类中,与设备类解耦。 -
数据结构
哈希表或字典:设备标识符与设备对象之间的映射,便于快速定位设备。
链表或数组:维护电路连接关系并实现按顺序遍历。 -
字符串处理
正则表达式:解析连接信息和控制指令的输入格式。
字符串分割与拼接:解析设备标识符和引脚信息。 -
电路模拟基础
电压分配规则:电压沿串联电路传递,并根据设备特性进行处理。
设备参数计算:包括亮度、转速等线性比例计算。 -
边界处理与错误校验
处理输入设备编号不连续或输入格式不完整的情况。
确保设备状态初始化、参数更新的完整性。 -
数学计算
小数截尾:用 Math.floor 或手动实现截尾规则。
比例计算:例如灯具亮度和风扇转速按电压差线性比例计算。 -
输入输出处理
标准输入流读取和解析。
格式化输出(特别是连续调速器档位保留两位小数)。
(3) 类图设计
(4) 踩坑心得
1.输入解析 (parseDeviceControl 和 parseCircuit)
职责:解析控制指令和连接信息,并更新设备状态或电路信息。
问题点:
parseCircuit 尚未实现完整逻辑,只是占位。
对控制设备的指令处理缺少边界检查(如设备编号不存在的情况)。
点击查看代码
static void parseDeviceControl(String line) {
if (line.startsWith("#K")) {
String deviceId = line.substring(1);
if (devices.containsKey(deviceId)) {
((Switch) devices.get(deviceId)).toggle();
}
} else if (line.startsWith("#L")) {
String[] parts = line.split(":");
String deviceId = parts[0].substring(1);
double value = Double.parseDouble(parts[1]);
if (devices.containsKey(deviceId)) {
((ContinuousSpeedController) devices.get(deviceId)).setSpeed(value);
}
}
}
优点:
使用字符串解析区分设备指令。
简单明了,通过类型转换实现多态行为。
改进建议:
增加异常处理和输入校验(如非法格式或编号)。
考虑扩展性,支持更复杂的指令(如增加分档调速器的加减档功能)。
2.设备类设计(Device 和子类)
职责:封装设备的状态和行为,使用继承和多态实现不同设备的差异化逻辑。
设备基类 Device
点击查看代码
abstract static class Device {
String id;
Device(String id) {
this.id = id;
}
abstract String getStatus();
}
子类实现:Switch
点击查看代码
static class Switch extends Device {
boolean closed;
Switch(String id) {
super(id);
this.closed = false;
}
void toggle() {
closed = !closed;
}
@Override
String getStatus() {
return "@" + id + ":" + (closed ? "closed" : "turned on");
}
}
子类实现:ContinuousSpeedController
优点:
使用抽象类和继承,封装设备通用特性。
子类中实现独立逻辑,开关和调速器各自的状态更新规则清晰。
getStatus() 方法统一设备输出接口,便于管理。
改进建议:
将设备与节点关系解耦,增加 connectTo(Node node) 方法,方便后续扩展。
将计算逻辑(如灯的亮度、风扇转速)封装到设备类中,而非依赖外部实现。
3.设备输出逻辑
职责:将设备状态以特定格式输出。
问题点:
输出格式较为单一,且未处理设备间的连接或电路电压计算。
点击查看代码
static void outputDeviceStatus() {
for (Device device : devices.values()) {
System.out.println(device.getStatus());
}
}
遍历设备集合,按顺序输出状态,逻辑简单直观。
改进建议:
在输出前,计算连接电路中的电压分布,动态更新设备的状态(如灯的亮度或风扇的转速)。
2.答题判题程序-4
(1) 难度分析
1.输入输出规则复杂性
输入格式多样,包括题目信息、试卷信息、学生信息、答卷信息、删除信息等。
输入信息可能无序,需要程序能够动态解析并正确关联。
输出格式要求严格(如顺序、格式化、警示信息、特殊提示等),需要逐步处理不同场景。
新增的多选题和填空题增加了输入解析和判题逻辑的复杂性。
-
信息关联与状态管理
输入信息之间存在复杂的关联关系,例如题目编号与试卷题目、学生答卷与试卷的关联。
删除题目信息需要更新所有相关引用,同时正确生成“失效提示”。
判分逻辑涉及多种情况(题目不存在、删除、多选部分正确等),需要精确判断和处理。 -
题型判题逻辑复杂性
包括填空题、多选题等新题型在内的多种题目需要动态解析并判分。
多选题和填空题的部分正确、全对、全错的判定规则需要详细实现,并影响得分计算。
判分中还需处理特殊情况,如题目被删除、引用错误等。 -
多条件排序与信息组织
输出要求按照学号、试卷号等排序,并优先处理特定提示信息(如题目不存在优先于被删除提示)。
信息组织需要设计合理的数据结构以支持高效的查找、修改、排序和输出。 -
边界条件处理
需考虑所有输入的合法性和完整性,如输入格式错误、缺少必要信息等。
输入信息可能不符合预期(如题号缺失、试卷引用不存在题号等),程序需要给出正确提示。
(2) 知识点分析
-
数据结构
Map: 用于存储题目信息、试卷信息、学生信息等,便于通过编号或ID快速查找。
List: 用于存储输入顺序,保证输出顺序符合要求。
Set: 用于处理多选题的标准答案和学生答案比较,快速判断是否包含正确选项。
PriorityQueue 或自定义 Comparator: 用于按学号、试卷号排序输出。 -
字符串处理
正则表达式: 用于解析输入格式(如题目编号、标准答案)。
字符串分割: 使用 split() 方法处理复杂输入数据。
字符串格式化: 使用 String.format 和 StringBuilder 拼接输出,保证格式一致。 -
算法逻辑
多选题和填空题的部分正确判分: 涉及集合操作(如交集、差集)和数学计算(如取整)。
总分计算与异常提示: 动态计算分值,同时判断异常条件输出提示。 -
面向对象设计
类设计:
题目类: 基类和子类(如填空题、多选题、普通题)。
试卷类: 包含题目及分值信息。
学生类: 包含学号、姓名和答题记录。
多态与继承: 不同题型的判题逻辑通过继承和多态实现,增加扩展性。 -
异常处理
输入合法性校验: 针对输入格式错误输出 wrong format: ...。
引用错误处理: 试卷号不存在、学号不存在、题目编号不存在等需特殊提示。 -
文件输入与多模块结构
模块化设计: 输入解析、判题逻辑、输出生成分模块实现,降低代码复杂度。
性能优化: 合理选择数据结构和算法,避免在大量数据下超时。
(3)类图设计
(4) 踩坑心得
- 输入解析复杂且冗长
输入格式种类多,正则表达式匹配逻辑复杂,稍有不慎容易出现解析失败或错误提示。
点击查看代码
private static void parseNormalQuestion(String line) {
String regex = "#N:(\\d+) #Q:(.+) #A:(.+)";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(line);
if (matcher.matches()) {
int questionNumber = Integer.parseInt(matcher.group(1));
String questionContent = matcher.group(2);
String answer = matcher.group(3);
if (questions.containsKey(questionNumber)) {
outputs.add("duplicate question number: " + questionNumber);
return;
}
questions.put(questionNumber, new Question(questionNumber, questionContent, answer, QuestionType.NORMAL));
} else {
outputs.add("wrong format:" + line);
}
}
每种输入类型单独实现解析逻辑,导致代码冗长。
输入正则可能不够灵活,例如对空格和格式的容错性不足。
优化建议:
将输入解析逻辑抽象为一个统一模块,支持动态扩展。
增强正则表达式的容错能力,忽略首尾空格等异常。
- 多选题和填空题的部分正确评分实现不足
问题分析:
多选题部分正确的评分逻辑只关注“是否完全正确”或“完全包含正确答案”,没有考虑部分正确的分数计算。
填空题的部分匹配逻辑完全未实现。
点击查看代码
case MULTIPLE_CHOICE:
Set<String> correctAnswers = new HashSet<>(Arrays.asList(question.answer.split(" ")));
Set<String> studentAnswers = new HashSet<>(Arrays.asList(answer.split(" ")));
if (studentAnswers.equals(correctAnswers)) {
return true;
} else if (studentAnswers.containsAll(correctAnswers)) {
return true;
} else {
return false;
}
多选题部分正确评分逻辑:
如果包含所有正确答案且无错误答案,满分。
如果包含部分正确答案且无错误答案,得一半分。
如果包含错误答案或完全无答案,0 分。
填空题部分正确评分逻辑:
可通过字符串相似度算法(如 Levenshtein 距离)计算答案相似程度。
- 优先级混乱的异常处理
多个异常(如题目不存在、答案为空、题目被删除)之间未明确优先级,可能导致输出不一致。
点击查看代码
if (deletedQuestions.contains(questionNumber)) {
outputs.add("the question " + questionNumber + " invalid~0");
result.append("0 ");
continue;
}
if (!questions.containsKey(questionNumber)) {
outputs.add("non-existent question~0");
result.append("0 ");
continue;
}
String answer = studentAnswers.getOrDefault(i + 1, "answer is null");
if (answer.equals("answer is null")) {
outputs.add("answer is null");
result.append("0 ");
}
问题分析:
输出的顺序和优先级可能因代码顺序错误而混乱。
当多种异常同时发生时(如答案为空且题目被删除),应优先输出高优先级提示。
优化建议:
定义异常优先级:
答案为空。
题目不存在。
题目被删除。
按优先级依次检查并输出。
三.大作业心得
在完成家居强电电路模拟程序-1和考试判题系统的开发过程中,我深刻体会到以下几点:
-
现实问题建模与抽象能力
无论是模拟电路还是考试评分,现实场景往往比程序复杂。为了让程序能准确反映现实问题,抽象出合适的数据结构和逻辑是关键。例如,在电路模拟中,我们用设备类和节点关联电路状态;在判题系统中,采用题目类和试卷类来动态管理数据。只有经过深思熟虑的抽象,才能设计出既灵活又高效的程序结构。 -
模块化设计和职责分离的重要性
两个项目都要求对输入解析、逻辑处理和输出生成进行清晰的分离。模块化设计不仅让代码更易维护,还能降低出错的概率。例如,在电路模拟中,设备和电路连接的逻辑分离,使得扩展新设备变得简单。在判题系统中,通过抽象不同题型的评分逻辑,确保了每种题型评分的准确性和独立性。 -
细节处理与异常处理能力
边界条件是程序的试金石。模拟电路时,要考虑无效连接、设备状态冲突等问题;判题系统中,需要处理无答案、多选部分正确等复杂情况。针对这些细节,提前设计好错误优先级和异常输出逻辑,能够大大提升程序的健壮性和可用性。 -
面向对象思想与灵活扩展
两个项目中都深刻体现了面向对象设计的威力。通过继承和多态,可以轻松扩展新的设备、新的题型或新的功能,而不影响原有代码。例如,在电路模拟中,通过增加继承类实现了开关设备和调速器设备的区别;在判题系统中,通过 enum 和多态封装了不同题型的评分规则。 -
测试和调试的重要性
对于复杂的输入规则和输出要求,开发中往往需要反复测试和调试。通过单元测试覆盖多种场景,验证程序逻辑和边界条件,可以有效避免后期的功能遗漏或错误输出。
四.总结
无论是家居电路模拟还是考试判题系统,它们都不仅仅是功能实现的练习,更是对编程能力、逻辑思维和问题解决能力的综合提升。在开发过程中,我们不断遇到挑战,但每一次解决问题的过程,都让我们更加理解了编程的本质:用清晰的逻辑和高效的工具解决复杂的现实问题。
标签:输出,总结性,题目,逻辑,Blog,电路,输入,设备 From: https://www.cnblogs.com/yoliny/p/18564625