JAVA第二次BLOG作业
目录
前言
设计与分析
PTA第四次作业
PTA第五次作业
PTA第六次作业
踩坑心得
总结
前言
这几次的大作业总的来说都花了很多的时间,也有做不出来的,但是一直做总能学到一些什么。每次我认为比较花时间的是怎么去设计好类,第六次则要想清楚怎么处理输入的电器以及电器的电压、电阻、甚至是电流,因为第六次和第五次不一样,第五次是只有串联,而第六次则是串并混用。使用继承还是用接口我认为都是可以做的,但有些情况是有更好的选择,这几次作业给我的感觉是,测试点要自己找,很多时候测试样例过了,才有了一些分数。
设计分析
PTA第四次作业
第四次大作业比第三次大作业多了多选题的判题,我对多选题的设计我采用的是继承Question类,定义了 Question、MultipleChoiceQuestion、FillInBlankQuestion、TestPaper、Student 、ExamSystem和 AnswerSheet 类来存储题目、试卷、学生和答卷信息。parseInput 方法解析输入信息并存储到相应的数据结构中。checkTestPaperScores 方法检查每张试卷的总分是否为100。gradeAnswers 方法对学生的答案进行评判,并生成输出信息。在 gradeAnswers 方法中生成答题信息、判分信息和提示信息。
类图:
顺序图:
设计思路
数据结构设计:
使用字典来存储题目信息、试卷信息、学生信息、答卷信息和删除题目信息。
题目信息字典:键为题目编号,值为题目对象(包含题目内容、标准答案、题目类型等)。
试卷信息字典:键为试卷号,值为试卷对象(包含题目编号-分值对)。
学生信息字典:键为学号,值为学生名字。
答卷信息字典:键为试卷号-学号对,值为答案列表。
删除题目集合:包含所有被删除的题目编号。
功能模块划分:
输入解析模块:负责解析用户输入的各种信息,将其转换成系统内部的数据结构。
试卷检查模块:检查试卷总分是否为100分,如果不是则生成警示信息。
答题判分模块:根据题目信息和学生的答案计算分数,并生成详细的答题信息。
输出模块:根据系统内部的数据结构生成符合要求的输出格式。
异常处理:
对于输入格式错误、题目引用错误、试卷号或学号引用错误等情况,需要设计相应的异常处理机制,确保系统的健壮性。
关键步骤
初始化数据结构:
创建题目信息字典、试卷信息字典、学生信息字典、答卷信息字典和删除题目集合。
输入处理:
循环读取输入直到遇到"end"。
根据输入的第一字符(如#N、#T、#X、#S、#D)确定输入类型,调用相应的方法处理输入信息。
对于题目信息、试卷信息、学生信息、答卷信息和删除题目信息分别进行解析并存入对应的数据结构。
试卷检查:
遍历试卷信息字典,计算每张试卷的总分,如果不是100分则生成警示信息。
答题判分:
对于每一份答卷,根据试卷信息中的题目编号查找题目信息,对比学生的答案与标准答案,根据题目类型(选择题、填空题等)的不同计算得分。
特别注意处理被删除的题目、答案不存在、题目引用错误等情况。
生成输出:
按照题目信息、答题信息、判分信息、删除题目提示信息、题目引用错误提示信息的顺序生成输出。
注意输出顺序优先级为学号、试卷号,按从小到大的顺序先按学号排序,再按试卷号。
异常处理:
在解析输入信息时检查格式是否正确,对于格式错误的信息生成错误提示。
在处理答题信息时,检查试卷号和学号是否存在,对于不存在的试卷号或学号生成相应的错误提示。
1.类设计:
Question: 基础问题类,包含问题的ID、内容、答案和分数。
MultipleChoiceQuestion: 多选题类,继承自Question,支持部分正确的情况。
FillInBlankQuestion: 填空题类,继承自Question,支持大小写不敏感的答案。
TestPaper: 试卷类,包含试卷ID和问题集合。
Student: 学生类,包含学生ID和姓名。
AnswerSheet: 答题卡类,包含试卷ID、学生ID和学生的答案集合。
2.系统设计
ExamSystem 是整个系统的主控类,负责解析输入数据、管理题目、试卷、学生和答题卡,并进行评分。
3.输入解析
ExamSystem 提供了一个 parseInput 方法来解析输入数据。输入数据包括题目、试卷、学生和答题卡的信息,每种信息都有特定的格式标识符。
题目解析 (parseQuestion):
根据标识符(#N:、#Z:、#K:)创建不同类型的问题对象。
存储在 questions 集合中。
试卷解析 (parseTestPaper):
创建 TestPaper 对象,并将题目及其分数添加到试卷中。
存储在 testPapers 集合中。
学生解析 (parseStudent):
创建 Student 对象,并存储在 students 集合中。
答题卡解析 (parseAnswerSheet):
创建 AnswerSheet 对象,并将学生的答案添加到答题卡中。
存储在 answerSheets 列表中。
删除题目解析 (parseDeletedQuestion):
将已删除题目的ID存储在 deletedQuestions 集合中。
4.检查试卷总分
checkTestPaperScores 方法遍历所有试卷,检查每个试卷的总分是否为100分,如果不是,则发出警告。
5.评分答案
gradeAnswers 方法遍历所有答题卡,对每个答题卡进行评分:
获取对应的试卷和学生信息。
遍历试卷中的每个题目,检查学生的答案是否正确。
如果答案正确,累加题目分数。
如果是多选题或填空题且部分正确,累加部分分数。
输出评分结果。
PTA第五次作业
类图:
顺序图:
- 代码结构与逻辑
主要类和方法
Electric 类:
属性:s(设备类型标识符)、id(设备ID)、shuV(电压)、ofopen(开关状态)、speed(速度)、lin(连续值)。
方法:display()(显示设备状态)、regulate(String vs)(调节设备)、reshuV(double shuop)(设置电压)、fanhui()(返回设备类型的优先级)。
子类:
Kaiguan(开关):
方法:display()、regulate(String vs)、reshuV(double shuop)。
Fendang(分档调节器):
方法:display()、regulate(String vs)、reshuV(double shuop)。
Lianxu(连续调节器):
方法:display()、regulate(String vs)、reshuV(double shuop)。
Baichi(白炽灯):
方法:display()、reshuV(double shuop)。
Riguang(日光灯):
方法:display()、reshuV(double shuop)。
Diaoshan(吊扇):
方法:display()、reshuV(double shuop)。
主函数逻辑
输入处理:
使用 Scanner 读取标准输入。
解析输入数据,将连接信息和控制命令分别存储在 ArrayList 中。
设备创建:
根据连接信息创建相应的设备对象,并存储在 HashMap 中。
状态更新:
根据控制命令更新设备状态。
处理开关的开闭状态、分档调节器的档位变化、连续调节器的值设定等。
输出结果:
将所有设备按特定规则排序。
调用每个设备的 display() 方法输出最终状态。 - 优化建议
异常处理
输入验证:确保输入数据的格式正确,避免因输入错误导致程序崩溃。
if (!s.startsWith("[") && !s.startsWith("#K") && !s.startsWith("#F") && !s.startsWith("#L")) {
System.err.println("Invalid input format: " + s);
continue;
}
代码优化
提取公共方法:减少重复代码,提高代码可维护性。
private static String extractDeviceId(String command) {
Pattern pattern = Pattern.compile("#(.*)");
Matcher matcher = pattern.matcher(command);
if (matcher.find()) {
return matcher.group(1);
}
return "";
}
性能优化
数据结构选择:对于大规模数据,可以考虑使用更高效的数据结构,如 TreeMap 或 ConcurrentHashMap。
Map<String, Electric> map1 = new ConcurrentHashMap<>();
3. 扩展方向
图形用户界面
使用 Swing 或 JavaFX:提供图形用户界面,使用户可以更直观地操作和查看电路状态。
public class CircuitUI extends Application {
@Override
public void start(Stage primaryStage) {
Button btn = new Button("Run Simulation");
VBox vBox = new VBox(btn);
Scene scene = new Scene(vBox, 300, 250);
primaryStage.setTitle("Circuit Simulator");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
更多设备类型
新增设备:可以轻松添加更多类型的设备,只需继承 Electric 类并实现相应的方法。
class NewDevice extends Electric {
public NewDevice(String id) {
super("N", id);
}
@Override
public void display() {
System.out.printf("@N%s:%.2f\n", id, someProperty);
}
@Override
public void regulate(String vs) {
// 实现调节逻辑
}
@Override
public void reshuV(double shuop) {
// 实现电压设置逻辑
}
@Override
public int fanhui() {
return 7; // 返回优先级
}
}
多线程支持
异步处理:对于复杂的电路模拟,可以考虑使用多线程来提高处理速度。
ExecutorService executor = Executors.newFixedThreadPool(4);
for (Electric device : arraylist6) {
executor.submit(() -> {
device.display();
});
}
executor.shutdown();
PTA第六次作业
顺序图
设计思路
类结构
接口和抽象类
Controllable 接口:定义了一个 control(String command) 方法,用于处理控制命令。
Device 抽象类:所有电器设备的基类,定义了共有的属性和方法,如设备ID、输入电压、输出电压、电阻等。还定义了抽象方法 updateVoltage() 用于更新设备的电压状态。
具体设备类
Switch(开关):实现了 Controllable 接口,可以切换开闭状态。
GearSpeedRegulator(分档调速器):实现了 Controllable 接口,可以调节档位。
ContinuousSpeedRegulator(连续调速器):实现了 Controllable 接口,可以调节连续值。
IncandescentLamp(白炽灯):根据电压计算亮度。
FluorescentLight(日光灯):根据电压确定亮度。
CeilingFan(吊扇):根据电压计算转速。
FloorFan(落地扇):根据电压计算转速。
电路类
SeriesCircuit(串联电路):管理一组串联的设备,计算总电阻和电流。
ParallelCircuit(并联电路):继承自 Device 类,管理一组并联的串联电路,计算总电阻和电流。
辅助类
PinandDevice:负责处理输入数据,创建设备和电路对象,更新电路状态,并打印设备状态。
inputHandle:负责读取用户输入并调用 PinandDevice 的相关方法进行处理。
主要功能
输入处理:
读取用户输入,解析连接信息和控制命令。
根据连接信息创建设备和电路对象。
根据控制命令更新设备状态。
电路连接:
串联电路:管理一组串联的设备,计算总电阻和电流。
并联电路:管理一组并联的串联电路,计算总电阻和电流。
状态更新:
根据输入电压和电路连接关系,更新每个设备的电压和状态。
处理控制命令,更新设备的状态。
输出结果:
按照特定规则排序设备,并输出每个设备的状态。
详细分析
- 类结构和继承关系
Controllable 接口:定义了控制设备的基本方法。
Device 抽象类:提供了设备的基本属性和方法,定义了抽象方法 updateVoltage()。
具体设备类:每个设备类继承自 Device 类,实现了 updateVoltage() 方法,并根据需要实现了 control(String command) 方法。 - 输入处理
PinandDevice 类:
processConnection_S:处理串联电路的连接信息,创建设备和串联电路对象。
processConnection_p:处理并联电路的连接信息,创建并联电路对象。
createDevice:根据设备ID创建具体的设备对象。
processControlCommand:处理控制命令,更新设备状态。
Update_circuit_resistance:更新电路的总电阻和电流。
printDeviceStatus:按特定规则排序设备,并输出状态。
inputHandle 类:
input:读取用户输入,调用 PinandDevice 的方法处理连接信息和控制命令。 - 电路连接和状态更新
SeriesCircuit 类:
total_resistance:计算串联电路的总电阻。
setCurrent:设置串联电路的电流。
updateVoltage:更新串联电路中每个设备的电压和状态。
ParallelCircuit 类:
total_resistance:计算并联电路的总电阻。
updateVoltage:更新并联电路中每个串联电路的电流和设备的电压和状态。 - 输出结果
PinandDevice 类:
printDeviceStatus:按特定规则排序设备,并输出状态。
getTypeOrder:获取设备类型的优先级,用于排序。
优化方案:
异常处理
输入验证:确保输入数据的格式正确,避免因输入错误导致程序崩溃。
if (!line.startsWith("[") && !line.startsWith("#T") && !line.startsWith("#M") && !line.startsWith("#")) {
System.err.println("Invalid input format: " + line);
continue;
}
代码优化
提取公共方法:减少重复代码,提高代码可维护性。
private static String extractDeviceId(String command) {
Pattern pattern = Pattern.compile("#(.*)");
Matcher matcher = pattern.matcher(command);
if (matcher.find()) {
return matcher.group(1);
}
return "";
}
性能优化
数据结构选择:对于大规模数据,可以考虑使用更高效的数据结构,如 TreeMap 或 ConcurrentHashMap。
Map<String, Device> devices = new ConcurrentHashMap<>();
扩展方向
图形用户界面
使用 Swing 或 JavaFX:提供图形用户界面,使用户可以更直观地操作和查看电路状态。
public class CircuitUI extends Application {
@Override
public void start(Stage primaryStage) {
Button btn = new Button("Run Simulation");
VBox vBox = new VBox(btn);
Scene scene = new Scene(vBox, 300, 250);
primaryStage.setTitle("Circuit Simulator");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
更多设备类型
新增设备:可以轻松添加更多类型的设备,只需继承 Device 类并实现相应的方法。
class NewDevice extends Device {
public NewDevice(String id) {
super(id, 0); // 初始电阻为0
}
@Override
public void updateVoltage() {
// 实现电压更新逻辑
}
@Override
public void control(String command) {
// 实现控制逻辑
}
@Override
public String toString() {
return "@" + id + ":" + someProperty;
}
}
多线程支持
异步处理:对于复杂的电路模拟,可以考虑使用多线程来提高处理速度。
ExecutorService executor = Executors.newFixedThreadPool(4);
for (Device device : sortedDevices) {
executor.submit(() -> {
System.out.println(device.toString());
});
}
executor.shutdown();
踩坑心得
1.一个类和方法只做一件事,做到低耦合,不能牵一发而动全身
2.在方法中尽量少用选择语句,如if-else,降低圈复杂度
3.在一些相似的类如果可以抽象出一些共同的属性和方法,可以适当使用继承和多态
4.要多去了解Java强大的类库
5.需要加强自己对算法的学习
6.使用继承和多态可以大大降低代码复杂度,提高效率
总结
- 设计经验
类设计与继承
抽象类与接口:在第四次作业中,我们使用了抽象类Question和具体子类MultipleChoiceQuestion、FillInBlankQuestion,在第六次作业中使用了抽象类Device和接口Controllable。这些设计模式帮助我们更好地组织代码,提高复用性和扩展性。
单一职责原则:每个类和方法只做一件事,保持低耦合。例如,Question类只负责存储和处理题目信息,ExamSystem类负责整体流程控制。
数据结构设计
字典与集合:使用字典(如HashMap)存储题目、试卷、学生和答题卡信息,使用集合(如HashSet)存储删除的题目编号。这些数据结构使得数据查找和管理更加高效。
多级嵌套结构:在第六次作业中,使用了多级嵌套的数据结构来管理串并联电路,例如ParallelCircuit类中包含多个SeriesCircuit对象,这种设计能够灵活地表示复杂的电路结构。 - 实现经验
输入解析
解析策略:根据不同类型的输入(如题目、试卷、学生、答题卡、控制命令等),使用不同的解析策略。通过字符串匹配和正则表达式提取关键信息。
异常处理:在解析过程中加入异常处理,确保输入格式错误不会导致程序崩溃。例如,使用try-catch块捕获解析异常,并给出友好的错误提示。
功能模块划分
模块化设计:将系统划分为多个模块,每个模块负责一个特定的功能。例如,输入解析模块、试卷检查模块、答题判分模块和输出模块。这种设计使得代码结构清晰,易于维护。
方法拆分:将长方法拆分成多个小方法,每个方法只完成一个具体任务。这样可以降低方法的复杂度,提高可读性和可测试性。 - 优化经验
异常处理
输入验证:在解析输入数据时,确保数据格式正确。例如,使用正则表达式验证输入字符串的格式。
错误提示:对于格式错误或引用错误的数据,生成明确的错误提示信息,帮助用户快速定位问题。
代码优化
提取公共方法:减少重复代码,提高代码可维护性。例如,提取公共的字符串解析方法extractDeviceId。
数据结构选择:根据实际需求选择合适的数据结构。例如,在处理大量数据时,使用ConcurrentHashMap代替普通的HashMap。
性能优化
多线程支持:对于复杂的电路模拟,可以使用多线程来提高处理速度。例如,使用ExecutorService异步处理设备状态更新。
算法优化:优化算法,减少不必要的计算。例如,在计算电路总电阻和电流时,避免重复计算。 - 学习心得
面向对象编程
封装:将数据和方法封装在类中,提高代码的安全性和可维护性。
继承和多态:通过继承和多态,实现代码的复用和扩展。例如,Device类的子类可以重写父类的方法,实现特定的设备行为。
数据结构与算法
常用数据结构:熟练掌握常用的Java数据结构,如HashMap、HashSet、ArrayList等。
算法应用:学会在实际问题中应用合适的算法,提高程序的效率。例如,使用排序算法对设备进行排序。
Java类库
标准库:熟悉Java标准库中的常用类和方法,如Collections、Stream、Pattern、Matcher等。