题目一:答题程序设计与实现
功能解析
题目一要求设计一个模拟答题系统,功能包括:
题目管理:
输入题目信息,包括题号、内容和标准答案。
支持删除某些题目,使其无效化。
试卷管理:
输入试卷信息,包括试卷编号、包含的题目及每题分值。
验证试卷总分是否满足预设标准(如 100 分)。
学生答题管理:
输入学生信息和答题记录。
根据试卷信息和学生答案对比计算得分。
结果输出:
输出每个题目的答题结果(正确、部分正确或错误)。
输出学生得分及答题详情。
代码设计与关键模块
代码主要采用了面向对象设计,核心类包括:
Question:表示一个题目,包含题号、题干、标准答案及状态信息。
TestPaper:表示一张试卷,记录试卷编号、题目列表及分值分布。
Answer:表示一个学生提交的答案,包含学生编号、答题记录及对应得分。
Student:表示学生信息,包括学号和姓名。
类与方法详解
- Question 类
表示一道题目的基本信息。
属性:
num:题号(int)。
questions:题干内容(String)。
answer:标准答案(String)。
isTrue:题目是否有效(boolean)。
方法:
getNum():获取题号。
getAnswer():获取标准答案。
isIstrue():判断题目是否有效。
setIstrue(boolean):设置题目状态(有效/无效)。
示例:
Question q1 = new Question(1, "What is 2+2?", "4");
System.out.println(q1.getAnswer()); // 输出: 4
2. TestPaper 类
表示一张试卷及其结构。
属性:
count:试卷编号(int)。
nums:包含的题号列表(ArrayList
scores:对应题号的分值列表(ArrayList
方法:
getCount():获取试卷编号。
getNum():获取题号列表。
getScore():获取题目分值列表。
示例:
ArrayList
ArrayList
TestPaper test1 = new TestPaper(101, nums, scores);
System.out.println(test1.getScore()); // 输出: [10, 20, 30]
3. Answer 类
表示学生提交的一份答卷及答题记录。
属性:
num:试卷编号(int)。
id:学生编号(String)。
number:答题号列表(ArrayList
answers:学生的答案列表(ArrayList
scores:对应每题的得分列表(ArrayList
方法:
getNum():获取试卷编号。
getAnswers():获取学生答案列表。
getScores():获取得分列表。
setScores(ArrayList
示例:
ArrayList
ArrayList
Answer ans1 = new Answer(101, "20230001", numbers, answers);
System.out.println(ans1.getAnswers()); // 输出: [4, 3]
4. Student 类
表示一个学生的基本信息。
属性:
id:学号(String)。
name:姓名(String)。
方法:
getId():获取学号。
getName():获取姓名。
示例:
Student stu1 = new Student("20230001", "Alice");
System.out.println(stu1.getName()); // 输出: Alice
主类 Main 的解析
主类 Main 是答题程序的核心执行模块,其功能涵盖了:
数据的输入与解析:
解析题目信息、试卷信息、学生信息和答题记录。
校验输入格式是否正确,并将数据存储到对应的对象和列表中。
功能实现:
管理题目和试卷的动态操作,如删除题目。
根据试卷与答题记录,对学生答案进行比对,计算得分。
结果输出:
输出每道题的答题情况(正确、部分正确、错误)。
输出学生的总得分及得分详情。
核心结构与功能模块
Main 类由以下几部分组成:
- 数据存储与初始化
使用多个集合存储不同数据类型:
questionlist:存储所有题目。
testList:存储所有试卷。
studentArrayList:存储所有学生。
answerArrayList:存储所有答题记录。
delList:存储被标记为删除的题目编号。
代码示例:
ArrayList
ArrayList
ArrayList
ArrayList
ArrayList
2. 输入解析与处理
(1) 解析题目输入
通过正则表达式提取题目信息(如编号、题干、标准答案)。
创建 Question 对象并添加到 questionlist。
代码示例:
if (input.startsWith("#N:")) {
String pattern = "#N:(\d+) #Q:(.+) #A:(\d+)";
Pattern p = Pattern.compile(pattern);
Matcher question = p.matcher(input);
if (question.find()) {
Question qs = new Question(
Integer.parseInt(question.group(1)),
question.group(2),
question.group(3)
);
questionlist.add(qs);
} else {
System.out.println("wrong format:" + input);
}
}
功能:
通过正则表达式校验输入格式。
如果校验通过,将题目信息存入对象中。
(2) 解析试卷输入
试卷输入格式包含试卷编号、题号列表及其对应分值。
正则提取题号和分值后,创建 TestPaper 对象并存储。
代码示例:
else if (input.startsWith("#T:")) {
String testPattern = "^#T:(\d+)(?: (\d+-\d+))*";
Pattern testP = Pattern.compile(testPattern);
Matcher test = testP.matcher(input);
if (test.matches()) {
int count = Integer.parseInt(test.group(1));
ArrayList
ArrayList
Pattern pp = Pattern.compile("(\\d+)-(\\d+)");Matcher m = pp.matcher(input);while (m.find()) {questionnum.add(Integer.parseInt(m.group(1)));scorelist.add(Integer.parseInt(m.group(2)));}TestPaper newTest = new TestPaper(count, questionnum, scorelist);testList.add(newTest);
} else {System.out.println("wrong format:" + input);
}
}
(3) 解析学生与答题记录
学生信息:
格式:#X:<学生编号> <学生姓名>。
创建 Student 对象并存入 studentArrayList。
答题记录:
格式:#S:<试卷编号> <学生编号> #A:<题号>-<答案>。
提取答题记录及答案,创建 Answer 对象。
代码示例:
else if (input.startsWith("#X:")) {
String pattern = "(\d{8})\s(\w+)";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(input);
while (m.find()) {
String id = m.group(1);
String name = m.group(2);
Student newStudent = new Student(id, name);
studentArrayList.add(newStudent);
}
}
else if (input.startsWith("#S:")) {
String pattern = "^#S:(\d+) (\d{8}) ((?:#A:\d+-[\w\s]+)+)";
Pattern answerPattern = Pattern.compile(pattern);
Matcher m = answerPattern.matcher(input);
if (m.matches()) {
int count = Integer.parseInt(m.group(1));
String ID = m.group(2);
String answersPart = m.group(3);
ArrayList
ArrayList
Pattern answerMatcher = Pattern.compile("#A:(\\d+)-(\\w+)");Matcher ansMatcher = answerMatcher.matcher(answersPart);while (ansMatcher.find()) {nums.add(Integer.parseInt(ansMatcher.group(1)));answers.add(ansMatcher.group(2));}Answer newAnswer = new Answer(count, ID, nums, answers);answerArrayList.add(newAnswer);
} else {System.out.println("wrong format:" + input);
}
}
展开
3. 题目删除逻辑
支持通过 #D:<题号> 格式输入,标记题目为无效。
代码示例:
else if (input.startsWith("#D:")) {
String pattern = "^#D:N-(\d+)";
Pattern delp = Pattern.compile(pattern);
Matcher m = delp.matcher(input);
if (m.find()) {
delList.add(Integer.parseInt(m.group(1)));
for (int i : delList) {
for (int j = 0; j < questionlist.size(); j++) {
if (questionlist.get(j).getNum() == i) {
questionlist.get(j).setIstrue(false);
}
}
}
} else {
System.out.println("wrong format:" + input);
}
}
4. 答题结果计算与输出
根据试卷中的题号,从题目列表中查找对应题目。
对比学生答案和标准答案,判断答题结果:
全对:得满分。
部分正确:得一半分。
错误或无效题目:得 0 分。
代码示例:
for (TestPaper paper : testList) {
if (paper.getCount() == newAnswer.getNum()) {
for (int i = 0; i < paper.getNum().size(); i++) {
boolean questionFound = false;
boolean answerProvided = false;
boolean isValidQuestion = false;
// 查找题目for (Question question : questionlist) {if (paper.getNum().get(i) == question.getNum()) {questionFound = true;if (question.isIstrue()) {isValidQuestion = true;}break;}}// 比较答案for (int x = 0; x < newAnswer.getNumber().size(); x++) {if (i + 1 == newAnswer.getNumber().get(x)) {answerProvided = true;break;}}// 计算分数if (answerProvided && isValidQuestion) {// 正确性判定逻辑...}}
}
}
展开
5. 总分校验
验证试卷总分是否为 100 分:
if (totalScore != 100) {
System.out.println("alert: full score of test paper1 is not 100 points");
}
程序运行逻辑
输入解析:基于正则表达式处理多种输入类型,如题目、试卷、答题记录等。
String pattern = "#N:(\d+) #Q:(.+) #A:(\d+)";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(input);
if (m.find()) {
Question qs = new Question(...); // 创建题目
}
题目与试卷管理:
保存所有题目、试卷的有效信息。
支持通过编号删除题目。
答案对比与得分计算:
将学生答案与标准答案对比。
判定正确、部分正确和错误,分配对应得分。
if (allCorrect && !anyIncorrect) {
studentScore += paper.getScore().get(i);
} else if (correctCount > 0) {
studentScore += paper.getScore().get(i) / 2; // 部分得分
}
结果输出:
输出学生得分。
输出每道题的答题结果。
改进建议
输入验证模块化:
将不同输入类型的正则解析抽取为工具方法,提高复用性。
答题逻辑优化:
增加题目随机生成、打乱顺序的功能,模拟实际考试。
性能优化:
使用哈希表存储题目与答案,加快匹配与比对速度。
序列化支持:
实现题库和答题记录的存储与加载功能,提升系统实用性。
题目二:智能家居强电电路模拟系统
功能需求解析
设备管理:
包含多种设备类型,如开关(SwitchDevice)、调速器(SteppedSpeedController、ContinuousSpeedController)、灯具(WhiteIncandescentLamp、DaylightLamp)、风扇(FanDevice)。
每个设备有独特的属性和行为。
电路模拟:
电路由多个设备串联连接,输入电压通过设备链传递和处理。
设备状态控制:
支持通过命令调整设备状态,如切换开关、调节速度、设置参数等。
输出结果:
模拟电路后输出设备的状态或计算值(如灯的亮度、风扇的速度)。
设计与实现分析
系统设计采用面向对象编程,核心在于抽象设备行为、设备继承关系,以及电路的拓扑管理。
类图
以下是该题目的类图,用于描述设备继承结构和电路管理的关系:
各类与方法介绍
- Device 类
设备的抽象基类,定义了设备的通用属性和行为。
属性:
id:设备唯一标识符。
type:设备类型(如开关、调速器等)。
number:设备编号。
方法:
getOutputVoltage(double inputVoltage):根据输入电压计算输出电压,子类需实现。
2. ControlDevice 类
继承 Device,表示控制设备,用于调节电压或控制设备链的状态。
方法:
toggle():切换设备的状态(如开关开启或关闭)。
2.1 SwitchDevice 类
开关设备,用于控制电路的通断。
属性:
state:开关状态(0 为开通,1 为关闭)。
方法:
getOutputVoltage(double inputVoltage):如果开关关闭,输出电压为输入电压;如果开关开启,输出为 0。
toggle():切换开关状态。
代码示例:
SwitchDevice switchDevice = new SwitchDevice("K1", 1);
switchDevice.toggle(); // 切换状态
System.out.println(switchDevice.getOutputVoltage(220)); // 输出电压
2.2 SteppedSpeedController 类
分档调速器,用于调节电压分级输出。
属性:
currentStep:当前档位(0-3)。
方法:
getOutputVoltage(double inputVoltage):根据当前档位输出比例电压。
increaseStep():提高档位。
decreaseStep():降低档位。
代码示例:
SteppedSpeedController controller = new SteppedSpeedController("F1", 1);
controller.increaseStep(); // 提高档位
System.out.println(controller.getOutputVoltage(220)); // 输出电压
2.3 ContinuousSpeedController 类
连续调速器,用于根据参数比例调节输出电压。
属性:
parameter:调节比例(0.00-1.00)。
方法:
getOutputVoltage(double inputVoltage):按比例输出电压。
setParameter(double newParam):设置新的调节比例。
代码示例:
ContinuousSpeedController continuousController = new ContinuousSpeedController("L1", 1);
continuousController.setParameter(0.5); // 设置比例
System.out.println(continuousController.getOutputVoltage(220)); // 输出电压
3. ControlledDevice 类
继承 Device,表示受控设备,用于模拟响应电压变化的设备状态。
方法:
computeState(double inputVoltage):根据输入电压计算设备状态。
getOutputVoltage(double inputVoltage):受控设备不改变电压,直接输出 0。
3.1 WhiteIncandescentLamp 类
白炽灯设备,亮度根据输入电压计算。
属性:
brightness:灯的亮度(0-200)。
方法:
computeState(double inputVoltage):根据输入电压计算亮度。
getBrightness():返回当前亮度。
3.2 DaylightLamp 类
日光灯设备,亮度为两种状态(0 或 180)。
属性:
brightness:灯的亮度(0 或 180)。
方法:
computeState(double inputVoltage):根据输入电压切换亮度。
3.3 FanDevice 类
风扇设备,转速根据输入电压计算。
属性:
speed:风扇转速(0-360)。
方法:
computeState(double inputVoltage):根据输入电压计算转速。
getSpeed():返回当前转速。
代码示例:
FanDevice fan = new FanDevice("D1", 1);
fan.computeState(100); // 输入电压
System.out.println(fan.getSpeed()); // 输出转速
主类 Main 的解析
主类 Main 是智能家居强电电路模拟系统的核心控制模块,负责以下主要任务:
输入解析与设备链初始化:
解析输入的设备链配置(连接格式)和命令(操作格式)。
创建设备实例并构建电路连接。
电路仿真:
模拟电压从电源(VCC)传递到地(GND)的过程。
通过设备链传递电压并计算各设备状态。
命令执行:
根据用户输入的命令调整设备状态(如切换开关、调节调速器档位或参数)。
输出设备状态:
按设备类型和编号顺序,输出每个设备的状态或计算值。
核心逻辑模块
- 数据存储与初始化
主类初始化时,存储输入数据,并构建设备链及命令列表:
设备链存储:通过 List
设备映射:通过 Map<String, Device> 存储设备的唯一标识符(如 K1、D2)与设备实例的映射关系,便于快速查询。
命令列表:存储命令行用于状态调整。
代码示例:
List
List
Map<String, Device> devicesMap = new HashMap<>();
List
2. 设备链解析
输入的设备链格式(如 [VCC K1-1] [K1-2 D2-1] [D2-2 GND])表示设备的连接关系。
每个连接点由两个端口组成,解析端口并确定设备的输入输出。
根据设备类型和编号创建相应的设备实例(通过 Device 子类)。
按设备连接顺序,依次构建设备链。
代码示例:
for (String conn : connectionLines) {
String content = conn.substring(1, conn.length() - 1).trim();
String[] pins = content.split("\s+");
if (pins.length != 2) continue;
String pinA = pins[0];
String pinB = pins[1];
String deviceId = pinB.split("-")[0];// 根据设备类型创建设备实例
Device device = devicesMap.getOrDefault(deviceId, createDevice(deviceId));
if (device != null && !deviceChain.contains(device)) {deviceChain.add(device);devicesMap.put(deviceId, device);
}
}
辅助方法:
private Device createDevice(String deviceId) {
char type = deviceId.charAt(0); // 获取设备类型(K, F, L, B, R, D)
int number = Integer.parseInt(deviceId.substring(1));
switch (type) {case 'K': return new SwitchDevice(deviceId, number);case 'F': return new SteppedSpeedController(deviceId, number);case 'L': return new ContinuousSpeedController(deviceId, number);case 'B': return new WhiteIncandescentLamp(deviceId, number);case 'R': return new DaylightLamp(deviceId, number);case 'D': return new FanDevice(deviceId, number);default: return null; // 未知设备类型
}
}
3. 命令解析与执行
用户输入的命令控制设备状态(如切换开关、调节调速器档位等)。命令格式包括:
切换开关:#K1 表示切换开关 K1。
调节档位:#F1+ 或 #F1- 表示增加或减少档位。
设置参数:#L1:0.5 表示将调速器 L1 的参数设置为 0.5。
逻辑处理:
遍历命令列表,根据命令类型操作对应设备。
代码示例:
for (String cmd : commandLines) {
if (cmd.startsWith("#K")) { // 切换开关
String deviceId = cmd.substring(1);
Device device = devicesMap.get(deviceId);
if (device instanceof SwitchDevice) {
((SwitchDevice) device).toggle();
}
} else if (cmd.startsWith("#F")) { // 调节分档控制器
String deviceId = cmd.substring(1, cmd.length() - 1);
char operation = cmd.charAt(cmd.length() - 1);
Device device = devicesMap.get(deviceId);
if (device instanceof SteppedSpeedController) {
if (operation == '+') ((SteppedSpeedController) device).increaseStep();
else if (operation == '-') ((SteppedSpeedController) device).decreaseStep();
}
} else if (cmd.startsWith("#L")) { // 设置连续控制器参数
String[] parts = cmd.split("😊;
String deviceId = parts[0].substring(1);
double param = Double.parseDouble(parts[1]);
Device device = devicesMap.get(deviceId);
if (device instanceof ContinuousSpeedController) {
((ContinuousSpeedController) device).setParameter(param);
}
}
}
4. 电路仿真
电路仿真是主类的核心逻辑:
起始电压:从 VCC 开始,初始电压为 220V。
电压传递:通过设备链依次传递电压,并计算各设备状态。
电压终止:到达 GND 后,电压归零。
核心代码:
double currentVoltage = 220.0; // 起始电压
for (Device device : deviceChain) {
if (device instanceof ControlDevice) {
currentVoltage = ((ControlDevice) device).getOutputVoltage(currentVoltage);
} else if (device instanceof ControlledDevice) {
((ControlledDevice) device).computeState(currentVoltage);
currentVoltage = 0.0; // 受控设备后电压归零
}
}
5. 输出设备状态
按设备类型和编号顺序,输出每个设备的状态或计算值。
排序逻辑:先按设备类型排序(K, F, L, B, R, D),再按编号排序。
设备状态:
开关设备:ON 或 OFF。
调速器:当前档位或比例参数。
灯具:亮度值。
风扇:转速值。
代码示例:
List
outputDevices.sort((d1, d2) -> {
String typeOrder = "KFLBRD";
int typeCompare = typeOrder.indexOf(d1.type) - typeOrder.indexOf(d2.type);
return typeCompare != 0 ? typeCompare : Integer.compare(d1.number, d2.number);
});
for (Device device : outputDevices) {
System.out.println("@" + device.id + ":" + device.getOutputString());
}
运行流程总结
解析输入:
解析设备连接并生成设备链。
解析命令并存储待执行操作。
执行仿真:
模拟电压传递,逐个设备处理电压并计算状态。
调整状态:
根据命令调整设备行为。
输出结果:
按顺序输出设备状态。
运行逻辑解析
输入解析:
输入设备链连接(如 [VCC K1-1] [K1-2 D1-1] [D1-2 GND]),逐步创建设备并连接。
命令解析(如 #K1 切换开关,#F1+ 增加档位)。
电路模拟:
电压从 VCC 端开始传递,每个设备处理后更新输出电压,直到到达 GND。
结果输出:
输出每个设备的状态或计算值。
改进建议
增加并联电路支持:
支持复杂的并联拓扑结构。
设备扩展性:
新增如智能插座、调光灯等设备类型。
性能优化:
引入缓存机制,避免重复计算状态。
题目三:智能家居系统迭代改进
功能需求解析
本题是对智能家居强电电路模拟系统(题目二)的迭代优化,新增了以下功能和改进:
并联与串联电路的组合:
引入 Circuit 抽象接口,支持串联电路(SerialCircuit)与并联电路(ParallelCircuit)的组合模拟。
模拟复杂电路拓扑结构(如多个支路并联的电路)。
设备工厂模式:
使用 DeviceFactory 动态创建设备实例,简化设备实例化逻辑。
改进的电路模拟:
支持递归地分配电压到并联和串联组件。
提高代码的可读性和扩展性。
命令解析与设备控制优化:
支持更复杂的命令输入,如切换开关、调整调速器档位等。
独立的命令执行模块便于扩展。
类图
以下是本题设计的类图:
类与方法解析
- Device 接口
表示一个设备的通用行为,定义了设备必须实现的两个方法:
方法:
getOutputString():返回设备的状态字符串(如开关状态、灯亮度、风扇转速)。
distributeVoltage(voltage, deviceVoltages):根据输入电压计算设备状态,并将电压分配给后续设备。
2. SwitchDevice 类
开关设备,继承自 Device,用于控制电路的通断。
属性:
isOn:开关状态,true 表示开启,false 表示关闭。
方法:
toggle():切换开关状态。
getOutputString():返回开关状态(如 ON 或 OFF)。
distributeVoltage(voltage, deviceVoltages):
如果开关关闭,则输出电压为 0。
如果开关开启,则传递输入电压。
3. SteppedSpeedController 类
分档调速器,用于分级调节电压。
属性:
step:当前档位(0-3)。
方法:
increaseStep():提高档位。
decreaseStep():降低档位。
getOutputString():返回当前档位。
distributeVoltage(voltage, deviceVoltages):根据档位输出比例电压。
4. ContinuousSpeedController 类
连续调速器,用于按比例调节输出电压。
属性:
parameter:调节比例(0.00-1.00)。
方法:
setParameter(double param):设置比例。
getOutputString():返回当前比例。
distributeVoltage(voltage, deviceVoltages):按比例输出电压。
5. WhiteIncandescentLamp 和 FanDevice 类
分别表示灯具和风扇设备,受输入电压控制。
方法:
computeState(double voltage):根据输入电压计算亮度或转速。
getOutputString():返回亮度或转速值。
distributeVoltage(voltage, deviceVoltages):设备不改变电压,传递 0。
6. Circuit 接口
表示一个电路结构,支持递归的电路拓扑组合。
方法:
addComponent(Circuit component):向电路中添加子组件(设备或子电路)。
distributeVoltage(voltage, deviceVoltages):将输入电压分配到子组件。
7. SerialCircuit 类
串联电路实现。
属性:
components:存储串联的子组件。
方法:
addComponent(Circuit component):添加设备或电路。
distributeVoltage(voltage, deviceVoltages):将输入电压按顺序传递给每个组件。
8. ParallelCircuit 类
并联电路实现。
属性:
branches:存储并联的子电路或设备。
方法:
addComponent(Circuit component):添加设备或电路。
distributeVoltage(voltage, deviceVoltages):将输入电压均分给每个分支。
9. DeviceCircuit 类
用于将单个设备适配为电路组件。
属性:
device:引用一个设备。
方法:
distributeVoltage(voltage, deviceVoltages):分配电压到设备。
addComponent(Circuit component):不支持子组件。
10. DeviceFactory 类
设备工厂,负责动态生成设备实例。
属性:
devicesMap:缓存所有创建的设备,避免重复创建。
方法:
getDevice(String deviceId):根据设备 ID 创建或返回设备实例。
getAllDevices():返回所有已创建的设备。
主类 Main 的核心逻辑
主类负责集成设备与电路管理,主要功能如下:
解析输入:
解析设备链连接(串联和并联)。
使用 DeviceFactory 动态生成设备实例。
构建电路:
将设备与子电路组合为主电路(SerialCircuit 或 ParallelCircuit)。
支持嵌套组合。
处理命令:
执行状态调整命令(切换开关、调节调速器档位等)。
电路仿真与输出:
仿真电路电压传递,输出设备状态。
主类 Main 的解析
主类 Main 是整个智能家居系统的核心控制模块,负责将各个功能模块(如设备创建、电路构建、命令执行、电路仿真等)集成到一起,实现整体逻辑。它的功能主要分为以下几部分:
- 输入解析与数据初始化
解析设备和电路结构
输入数据中描述了电路结构,分为两部分:
电路连接关系:
输入格式如 [VCC K1-1] [K1-2 D1-1] [D1-2 GND],表示设备及其连接点。
主类解析输入,动态创建设备实例,并通过 SerialCircuit 或 ParallelCircuit 构建完整电路。
实现逻辑:
利用 DeviceFactory 动态创建设备。
根据连接关系,将设备包装成 DeviceCircuit,再添加到对应的 SerialCircuit 或 ParallelCircuit 中。
代码示例:
List
"[VCC K1-1]",
"[K1-2 F1-1]",
"[F1-2 D1-1]",
"[D1-2 GND]"
);
Map<String, Device> deviceMap = new HashMap<>();
DeviceFactory deviceFactory = new DeviceFactory();
SerialCircuit mainCircuit = new SerialCircuit();
for (String conn : connections) {
String[] parts = conn.replaceAll("[\[\]]", "").split(" ");
String deviceId = parts[1].split("-")[0];
Device device = deviceFactory.getDevice(deviceId);
if (!deviceMap.containsKey(deviceId)) {
deviceMap.put(deviceId, device);
}
mainCircuit.addComponent(new DeviceCircuit(device));
}
解析命令
命令输入用于控制设备状态,例如:
切换开关:#K1
增加档位:#F1+
调整比例:#L1:0.5
实现逻辑:
逐行读取命令,解析操作类型和目标设备。
根据设备类型调用对应方法调整状态。
代码示例:
List
"#K1",
"#F1+",
"#L1:0.5"
);
for (String cmd : commands) {
if (cmd.startsWith("#K")) { // 开关切换
String deviceId = cmd.substring(1);
Device device = deviceMap.get(deviceId);
if (device instanceof SwitchDevice) {
((SwitchDevice) device).toggle();
}
} else if (cmd.startsWith("#F")) { // 调节分档控制器
String deviceId = cmd.substring(1, cmd.length() - 1);
char operation = cmd.charAt(cmd.length() - 1);
Device device = deviceMap.get(deviceId);
if (device instanceof SteppedSpeedController) {
if (operation == '+') ((SteppedSpeedController) device).increaseStep();
else if (operation == '-') ((SteppedSpeedController) device).decreaseStep();
}
} else if (cmd.startsWith("#L")) { // 设置连续控制器参数
String[] parts = cmd.split("😊;
String deviceId = parts[0].substring(1);
double param = Double.parseDouble(parts[1]);
Device device = deviceMap.get(deviceId);
if (device instanceof ContinuousSpeedController) {
((ContinuousSpeedController) device).setParameter(param);
}
}
}
展开
2. 电路仿真
分配电压
电路仿真通过递归分配电压来模拟电路行为:
起始电压:
电源 VCC 的初始电压为 220V。
递归传递:
串联电路:按顺序传递电压。
并联电路:将电压均分给所有分支。
实现逻辑:
调用 SerialCircuit 和 ParallelCircuit 的 distributeVoltage 方法分配电压。
通过 DeviceCircuit 调用设备的 distributeVoltage 方法计算设备状态。
代码示例:
double initialVoltage = 220.0;
Map<Device, Double> deviceVoltages = new HashMap<>();
mainCircuit.distributeVoltage(initialVoltage, deviceVoltages);
// 分配后的设备状态
for (Map.Entry<Device, Double> entry : deviceVoltages.entrySet()) {
Device device = entry.getKey();
double voltage = entry.getValue();
System.out.println("Device: " + device.getOutputString() + " Voltage: " + voltage);
}
设备状态更新
每个设备根据分配到的电压更新自身状态:
开关:判断是否导通。
调速器:根据档位或参数调整输出电压。
灯具/风扇:根据输入电压计算亮度或转速。
示例代码:
for (Device device : deviceMap.values()) {
if (device instanceof ControlledDevice) {
((ControlledDevice) device).computeState(deviceVoltages.get(device));
}
}
3. 输出结果
输出设备状态
按设备类型和编号顺序,输出每个设备的状态。
开关:ON 或 OFF。
调速器:当前档位或比例参数。
灯具:亮度值。
风扇:转速值。
代码示例:
List
devices.sort((d1, d2) -> {
String typeOrder = "KFLBRD";
int typeCompare = typeOrder.indexOf(d1.getClass().getSimpleName().charAt(0)) -
typeOrder.indexOf(d2.getClass().getSimpleName().charAt(0));
return typeCompare != 0 ? typeCompare : Integer.compare(d1.getNumber(), d2.getNumber());
});
for (Device device : devices) {
System.out.println("@" + device.getId() + ":" + device.getOutputString());
}
主类 Main 的主要功能总结
输入解析:
构建设备和电路结构,支持串联与并联组合。
动态解析命令,支持灵活的设备控制。
电路仿真:
模拟电压传递和设备状态更新。
支持复杂的电路拓扑结构(递归嵌套)。
结果输出:
输出电路仿真结果,包括设备的电压和状态。
运行逻辑总结
输入解析模块化:支持复杂的并联与串联组合。
设备工厂简化逻辑:通过 DeviceFactory 动态创建设备。
递归仿真电路:支持嵌套的电路拓扑结构。
结果输出清晰:输出
所有设备的状态或结果值。
心得体会
- 面向对象设计的重要性
这三题的核心在于如何使用面向对象设计原则来模拟复杂系统。尤其是设备与电路的建模,体现了以下几方面的价值:
抽象和继承:通过 Device 和 Circuit 的接口设计,实现了对设备和电路行为的抽象。设备的具体实现(如开关、调速器、灯具等)都可以遵循统一接口,便于扩展新设备类型。
组合优于继承:通过组合电路(串联与并联)代替继承,体现了灵活性和模块化的设计思想,便于递归处理复杂电路结构。
设计模式的运用:使用工厂模式 (DeviceFactory) 动态创建设备,解耦了主类与具体设备类型的关系,提高了系统的扩展性。
2. 代码组织与模块化的价值
将代码划分为多个独立模块,每个模块专注于完成一个任务,例如:
输入解析:专注于数据的格式校验与结构构建。
电路模拟:递归处理电压传递,独立封装串联与并联逻辑。
命令执行:单独处理用户命令,灵活扩展。
状态输出:负责统一的状态展示,易于维护。
这种模块化设计,不仅提高了代码的可读性和复用性,也便于后续的功能扩展和维护。
- 系统扩展性和灵活性
这些题目特别强调系统的扩展性:
扩展设备类型:
通过继承 Device 接口,能够轻松添加新的设备类型。
如需新增设备(如智能插座或调光灯),只需实现 distributeVoltage 和 getOutputString 方法。
扩展电路结构:
通过递归定义 Circuit 接口,支持任意复杂的嵌套电路结构。
新增电路类型(如混联电路)也变得相对容易。
扩展命令:
将命令解析与执行分离,便于新增操作逻辑(如远程控制或批量操作)。
4. 面对复杂系统的分步解决思路
三道题逐步增加了系统复杂度,从单一设备管理到递归电路模拟,再到支持并联和嵌套电路,充分体现了解决复杂系统问题的分步思路:
从简单到复杂:逐步增加功能(如从串联电路到并联电路),避免一次性解决所有问题。
分解问题:将复杂的电路问题拆解为子问题(如设备行为、电压分配、状态更新)。
测试驱动开发:每个模块完成后进行独立测试,确保其行为符合预期。
5. 教训与改进空间
教训
输入解析复杂性:
处理复杂的嵌套电路拓扑时,输入解析容易变得臃肿,正则表达式或字符串解析代码显得复杂。应该考虑引入更清晰的数据结构来描述输入格式。
性能优化:
如果设备数量或电路嵌套层次较多,递归仿真的性能可能成为瓶颈。可以考虑优化电压传递的算法或引入缓存机制。
错误处理:
系统对输入错误的容错能力需要加强,比如当命令中设备不存在或电路中连接有误时,应该给出更清晰的错误提示。
改进空间
输入解析改进:
可以采用 JSON 或 XML 格式作为输入结构,便于描述复杂的电路关系,同时简化解析逻辑。
测试覆盖:
增加单元测试和集成测试,覆盖更多的边界条件(如异常输入、电路短路、设备断电等)。
用户友好性:
提供更人性化的命令行界面(CLI)或图形用户界面(GUI),让用户能够直观地构建和模拟电路。
总结
这三道题目不仅是对面向对象设计和编程能力的考验,也是对解决复杂系统问题思维的锻炼。它让我深刻体会到:
分步解决问题的力量:通过逐步完善系统功能,可以有效降低复杂性。
面向对象设计的灵活性:良好的抽象设计让系统具备高度的扩展性和可维护性。
细节与整体的平衡:既要关注系统整体架构,也要注重每个模块的实现细节。
通过这次练习,我不仅巩固了面向对象设计的核心思想,还加深了对工程化开发方法的理解。这将对今后的开发工作提供宝贵的经验和参考。