java-BLOG-2
1.前言:
第四次题目集:
这次题目集的第一和第二个题目比较简单,很容易可以做出来,只是用到了一个新的知识点——继承,继承(Inheritance)是面向对象编程的核心特性之一。它允许一个类(子类)继承另一个类(父类)的属性和方法,从而实现代码复用和功能扩展。继承是通过extends关键字来实现的,子类可以继承父类的所有非私有(private)成员变量和方法。在子类中,可以通过super关键字访问父类的成员变量和方法,父类的构造函数不会自动被子类继承,但可以通过super()在子类构造函数中显式调用父类的构造函数,所以super关键字不仅可以用来访问父类的方法和变量,还可以用于调用父类的构造函数。而当子类需要修改父类的方法时,可以使用方法重写(@Override),在子类中重新定义与父类方法相同签名的方法,子类的方法会覆盖父类的方法,这样就可以指向明确,方便使用,使相同的方法不同的类达到不同的效果。对于第一二题,只需要用extends和super关键字就能完成。而第三题就比较复杂了。在之前题目的基础上选择题和填空题,选择题还包括单选和多选,无疑使题目复杂度更上一层楼。
第五、六次题目集:
从这俩次题目开始就是另一个新题目的迭代设计了,是一个居强电电路模拟程序。主要功能是计算电压和调节设备并显示设备信息。题目思路是设计电路设备主父类,继承了受控设备类、控制设备类、串联设备类、并联设备类。在受控设备类和控制设备类里编写各种设备信息,而在串并联电路写设备之间的连接信息和调整信息以及参数的计算。还有输入输出类,输入类是解析输入信息,输出类是保证输出的准确性和正确性。是对继承这一核心知识点的运用和理解,题量和复杂性是比较大的,对我来说是需要花费大量时间来写的。
2.设计与分析
第四次题目集-答题判题程序-4
(1)类图
(2)圈复杂度
1.代码结构
类结构:
Question:表示一个题目,包含ID、内容、答案和类型。
TestPaper:表示一份试卷,包含ID和题目列表。
QuestionScore:表示题目的得分信息。
Student:表示一个学生,包含ID和姓名。
AnswerSheet:表示一份答题卡,包含试卷ID、学生ID和答案。
数据结构:
questions:存储所有题目,键为题目ID。
testPapers:存储所有试卷,键为试卷ID。
students:存储所有学生,键为学生ID。
answerSheets:存储所有答题卡。
deletedQuestions:存储已删除的题目ID。
方法:
main:主入口,读取输入并处理。
processInput:根据输入类型调用相应处理方法。
processSingleChoiceQuestion、processMultipleChoiceQuestion、processFillInBlankQuestion:处理不同类型题目的输入。
processTestPaper:处理试卷的输入。
processStudent:处理学生的输入。
processAnswerSheet:处理答题卡的输入。
processDeleteQuestion:处理删除题目的输入。
calculateTotalScore:计算试卷总分。
outputTestPaperAlert:输出试卷分数不为100的警告。
outputStudentResult:输出学生的答题结果。
outputResults:输出所有结果。
第五次题目集-家居强电电路模拟程序-1
(1)类图
(2)圈复杂度
- 代码结构
Main 类:程序的入口,负责初始化 Scanner 和 Input 类,并调用 scanf 方法处理输入。
Input 类:处理从标准输入读取的数据,包括连接信息和设备调节信息。
SeriesCircuit 类:表示一个串联电路,包含设备管理、电压更新、状态更新和设备显示等功能。
ControlEquipment 接口:定义了设备的基本操作,如调整设备状态。
具体设备类:如 Switch、GearSpeedRegulator、ContinuousSpeedRegulator、IncandescentLamp、FluorescentLamp 和 CeilingFan,实现了 ControlEquipment 接口。
2.解释与心得
(1)根据符号的不同,分别创建设备
这段代码通过使用 switch 语句,根据设备名称的首字母来动态创建不同类型的设备对象,结构清晰且易于理解。它的优点在于:
1)清晰简洁:switch 语句将不同设备的创建逻辑清晰地划分为多个分支,使得代码易于阅读和理解。每个设备类型的逻辑都对应一个明确的 case,避免了混乱和复杂的条件判断。
2)易于扩展:如果将来需要支持更多设备类型,只需在 switch 语句中添加相应的 case 分支,不需要修改现有代码的其他部分。这样使得代码具备了良好的可扩展性。
3)集中管理:所有设备的创建逻辑都集中在 createDevice 方法中,便于后续的修改和维护。如果创建设备的逻辑发生变化,只需要在此方法中做调整,减少了分散修改的复杂度。
4)高效执行:相比于多个 if-else 语句,switch 语句在处理多个条件判断时通常会被编译成查找表或优化后的跳转代码,提供更高的执行效率,尤其在条件判断较多时性能优势更加明显。
5)减少冗余:通过集中管理设备创建逻辑,避免了代码中硬编码或重复的判断条件,使得代码更加简洁,减少了冗余部分,提高了代码质量和可维护性。
总的来说,这段代码通过 switch 语句实现了设备创建的高效、清晰、可扩展的逻辑,是一种良好的编程实践,适合于长期维护和扩展,如果之后还有别的设备需要创建,直接加个case就行,十分方便。
(2)对于输入的判断
不是把判断的代码一起写在这里,而是直接写在另一个函数里,当输入不是end时,跳转到processInput函数里,在这个函数里写对应得处理操作。优点在于通过使用 while 循环持续读取输入,直到遇到指定的终止条件 "end",保证了输入处理的灵活性和可控性。每次读取输入时,通过 trim() 方法去除两端空格,确保输入数据的整洁性,并通过 processInput() 方法对每一行输入进行处理,增强了代码的模块化和可维护性。整体逻辑简洁高效,能够适应动态输入,具有较好的扩展性和易于理解的结构。
第六次题目集-家居强电电路模拟程序-2
(1)类图
(2)圈复杂度
1.代码结构
Device 类:抽象基类,包含设备的基本属性和方法。
具体设备类:如 GearSpeedRegulator、ContinuousSpeedRegulator、Switch 等,继承自 Device 类,实现具体的功能。
SeriesCircuit 类:表示串联电路,包含多个设备,可以添加设备并执行操作。
ParallelCircuit 类:表示并联电路,包含多个串联电路,可以设置输入电压并执行操作。
设备速度调节:通过 adjust 方法调整齿轮调速器的速度。
连续调速器位置调整:通过 setPosition 方法设置连续调速器的位置。
串联电路处理:解析输入行,创建串联电路并添加设备。
并联电路处理:解析输入行,创建并联电路并添加串联电路。
设备创建:根据设备ID的首字母创建不同类型的具体设备对象。
操作所有并联电路:设置输入电压并执行操作。
打印所有设备状态:遍历所有设备并打印其状态信息。
2.解释与心得
(1)提取串联电路得设备
processConnection 方法的主要功能是解析一个特定格式的字符串(如 #T1:[IN K1-1] [K2-2 K3-1] [K4-2 OUT]),通过正则表达式提取其中的设备信息,并对每个设备标识符调用 processDevice 方法进行处理。首先,它使用一个正则表达式来匹配字符串,匹配成功后从中提取出设备 ID,例如 K1-1、K2-2 等。对于每个设备 ID,它提取出标识符部分(如 K1、K2),并传递给 processDevice 方法进行进一步处理。如果字符串格式不符合预期,方法会输出错误提示信息“Invalid input format”。该方法通过正则匹配和提取设备信息来自动化处理设备标识符,并确保输入符合特定格式。
(2)调整设备状态
这段代码的作用是根据不同的控制命令对设备进行操作。它通过检查传入的命令字符串的开头来判断是哪种操作,并从命令中提取相应的信息(如设备ID、动作类型、速度或位置)。具体地:
当命令以 #K 开头时,表示控制设备的开关。程序通过设备ID查找设备,并调用设备的 toggle() 方法切换设备的开关状态。
当命令以 #F 开头时,表示调整齿轮调速器的速度。程序提取调整方向(加速或减速),并通过设备ID找到相应的调速器,调用 adjust() 方法来增加或减少速度。
当命令以 #L 开头时,表示调整连续调速器的位置。程序从命令中提取新的位置值,并调用 setPosition() 方法设置该位置。
对于每种操作,代码都会检查设备是否存在于 devices 集合中,如果存在,则执行相应的操作。
3.踩坑心得
(1)对于大量设备的处理,可以考虑使用更高效的数据结构,如 HashMap 来存储设备,提高查找和更新的效率,同时HashMap 提供了丰富的 API,使得添加、删除和查找设备的操作非常简单和直观。
实现:
public class SeriesCircuit {
private Map<String, ControlEquipment> devices = new HashMap<>();
public void addDevice(ControlEquipment device) {
devices.put(device.getDeviceID(), device);
}
public void updateVoltages() {
for (ControlEquipment device : devices.values()) {
device.adjustVoltage();
}
}
}
(2)及时更新设备状态,如果设备状态更新不及时,会导致显示的信息不准确。
实现:在 SeriesCircuit 类中,确保每次处理连接信息后立即更新设备状态。
public void testDeviceStateUpdate() {
SeriesCircuit circuit = new SeriesCircuit("Circuit1", 1);
circuit.processConnection("[#K1]");
circuit.updateVoltages();
circuit.updateStates();
circuit.displayDevices();
assertTrue(System.out.toString().contains("@K1:0"));
}
(3)获取设备对象
问题:在获取设备对象时,需要进行类型转换,如 GearSpeedRegulator gear = (GearSpeedRegulator) devices.get(deviceId);。
解决:确保设备映射中存储的对象类型正确,避免运行时类型转换错误。
(4)设备ID重复问题
问题:如果设备ID重复,可能会导致设备对象被覆盖。
解决:在创建设备时,检查设备ID是否已存在,避免重复创建。
4.改进建议
(1)使用桥接模式,桥接模式(Bridge Pattern)可以使代码结构更加灵活,避免在单一类中大量的条件判断,并且使得设备控制逻辑和设备类型的操作解耦。具体的改进方式是,将不同的设备操作和具体设备类型的实现分开,使得新增设备类型或操作时,代码的修改不会互相影响,从而提升可维护性和扩展性。
改进后的优势:
1)解耦控制逻辑与设备类型:DeviceCommand 类和 DeviceControl 接口不再关心具体的设备类型实现,从而解耦了命令和设备。不同类型的设备可以共享相同的控制逻辑。
2)易于扩展:若未来需要支持新的设备类型,只需新增实现 DeviceControl 接口的设备类,而不必修改控制命令类。类似地,增加新的控制命令(如调整温度、方向等)也变得更加容易。
3)灵活的设备操作:通过桥接模式,可以为不同设备实现不同的操作方法,例如有些设备可以调整速度,有些设备则可能没有调整速度的功能。
4)代码更加清晰和简洁:避免了冗长的条件判断和类型检查,使得代码的可读性和可维护性大大提高。
(2)数据结构优化
设备列表:使用字典或哈希表来存储设备,以便快速查找和访问。
连接关系:使用图结构来表示设备之间的连接关系,便于处理复杂的连接信息。
(3)文档与注释
代码注释:为每个类和方法添加详细的注释,说明其功能和使用方法。
5.总结
随着实验难度的逐渐增加,题目变得越来越复杂。我深刻体会到,编写高质量代码的关键不仅在于技术层面的熟练度,更在于有一个清晰的头脑和合理的结构设计。面对复杂问题时,保持冷静,理清思路,将大问题分解成小问题逐步解决。设计时采用模块化和接口分离的方法,确保代码的可读性和可维护性。实现功能时,逐步推进,编写单元测试和集成测试,确保每一步都经过充分验证。此外,清晰的思路至关重要,通过需求分析、伪代码和代码审查来确保思路的正确性。通过不断的实践和学习,积累经验,提高解决问题的能力。希望这些总结和反思能够帮助我在未来的开发过程中不断提升,更好地应对复杂的编程挑战。最关键的是要预留充足的时间来写代码,不要留到周末来写,每次时间紧张的时候,我都会静不下心来写代码,再加上代码确实难,总会造成不好的结果。所以,最好前几天就能写好代码框架,实现部分样例的测试通过,然后最后几天,再一步步通过剩下的测试点,完善代码逻辑。