java4~6次题目集总结

本次完成了4~6次题目集分别是接着上一次的答题判题程序-4以及新一系列的家居强电电路模拟程序-1和家居强电电路模拟程序-2
答题判题程序-4比起前几次新增了不同的题型列如填空题多选题
家居强电电路模拟程序-1实现了一个家居电路串联控制不同设备计算电压以及各个设备参数的功能
家居强电电路模拟程序-2在家居强电电路模拟程序-1的基础上加入了并联电路的要求以及增加了设备等功能
接下来详细说明一下每个题目的具体逻辑以及重点的内容。

答题判题程序-4

1. 系统架构与功能

核心模块

  1. 题目类(BaseQuestion及其子类)

    • BaseQuestion:定义了基本属性和抽象评分方法。
    • NormalQuestionChoiceQuestionFillBlankQuestion:分别实现了普通题、选择题和填空题的具体评分逻辑。
  2. 试卷类(Paper)

    • 管理一组题目,通过题目ID进行关联。
    • 提供计算试卷总分的功能,遍历所有题目并调用其评分方法。
  3. 评分服务(ScoringService)

    • 统一管理多个试卷。
    • 提供对指定试卷进行评分的方法,并处理试卷不存在的异常情况。
  4. 测试类(TestScoringSystem)

    • 模拟了创建题目、试卷及评分的过程。
    • 提供了学生答案的模拟输入,并输出总得分。

2. 主要功能

  • 题目管理

    • 支持普通题、选择题和填空题的创建和管理。
    • 通过试卷类将不同题型的题目组织在一起。
  • 答案评分

    • 各题型实现了自己的评分逻辑,支持部分正确的处理。
    • 通过试卷类计算学生在整张试卷中的总得分。
  • 异常处理

    • 对试卷不存在的情况进行异常抛出,保障系统的健壮性。

下面是此程序的类图设计和顺序图设计
类图:

顺序图:

核心代码: 题目类及评分方法

// 基类:BaseQuestion
public abstract class BaseQuestion {
    protected int id;
    protected String content;
    protected String standardAnswer;
    protected boolean isDeleted = false;

    // 抽象方法:各子类需实现具体的评分逻辑
    public abstract int score(String studentAnswer);
}

// 普通题实现
public class NormalQuestion extends BaseQuestion {
    private int fullScore;

    public NormalQuestion(int id, String content, String standardAnswer, int fullScore) {
        this.id = id;
        this.content = content;
        this.standardAnswer = standardAnswer;
        this.fullScore = fullScore;
    }

    @Override
    public int score(String studentAnswer) {
        return standardAnswer.equals(studentAnswer) ? fullScore : 0;
    }
}

// 填空题实现
public class FillBlankQuestion extends BaseQuestion {
    private int fullScore;

    public FillBlankQuestion(int id, String content, String standardAnswer, int fullScore) {
        this.id = id;
        this.content = content;
        this.standardAnswer = standardAnswer;
        this.fullScore = fullScore;
    }

    @Override
    public int score(String studentAnswer) {
        String[] correctAnswers = standardAnswer.split("或");
        for (String correct : correctAnswers) {
            if (correct.trim().equalsIgnoreCase(studentAnswer.trim())) {
                return fullScore;
            }
        }
        return fullScore / 2; // 部分正确得分
    }
}

// 选择题实现
public class ChoiceQuestion extends BaseQuestion {
    private int fullScore;

    public ChoiceQuestion(int id, String content, String standardAnswer, int fullScore) {
        this.id = id;
        this.content = content;
        this.standardAnswer = standardAnswer;
        this.fullScore = fullScore;
    }

    @Override
    public int score(String studentAnswer) {
        String[] correctChoices = standardAnswer.split(" ");
        String[] studentChoices = studentAnswer.split(" ");
        int correctCount = 0;

        for (String choice : studentChoices) {
            if (Arrays.asList(correctChoices).contains(choice.trim())) {
                correctCount++;
            }
        }

        return (int) ((double) correctCount / correctChoices.length * fullScore);
    }
}

分析

  1. 评分方法的实现

    • 普通题(NormalQuestion:直接对比标准答案与学生答案,简单高效。
    • 填空题(FillBlankQuestion:支持多个正确答案,但部分正确得分的逻辑较为简化。
    • 选择题(ChoiceQuestion:实现了部分正确的逻辑,但未考虑重复选项对分数的影响。
  2. 代码复用性

    • 各题型的score方法实现类似,部分逻辑(如标准答案的分割和学生答案的比较)可以抽取到工具类中,提高复用性。
  3. 边界问题

    • 填空题
      • 需要考虑答案格式差异(大小写、空格等)的影响。
    • 选择题
      • 学生答案中重复选项可能导致得分不准确。

优点分析

  1. 良好的面向对象设计

    • 使用了 抽象类 BaseQuestion 提取公共属性和行为,避免重复代码,易于扩展新题型。
    • 子类根据不同题型实现 score 方法,符合开放-关闭原则(对扩展开放,对修改关闭)。
  2. 代码的可扩展性强

    • 可以方便地添加新题型,只需继承 BaseQuestion 并实现具体的评分逻辑,而无需改动已有代码。
    • 新题型可以拥有独特的逻辑,不受已有题型限制。
  3. 功能划分明确

    • 各题型(如 NormalQuestionFillBlankQuestionChoiceQuestion)的逻辑清晰,职责单一,易于维护。
  4. 灵活的评分逻辑

    • 每种题型的评分逻辑是独立的,可以灵活处理不同的需求。例如:
      • FillBlankQuestion 支持多个标准答案。
      • ChoiceQuestion 支持部分正确得分。
  5. 代码结构简洁清晰

    • 使用合适的属性和方法,且构造函数初始化充分,避免了过度设计或冗余。

缺点分析

  1. 硬编码问题

    • 某些评分逻辑直接依赖字符串处理,如 FillBlankQuestion 中通过 split("或")ChoiceQuestion 中通过空格分隔。这种逻辑对格式要求严格,且不够灵活,容易出错。
    • 需要对 standardAnswerstudentAnswer 的输入格式严格规范,否则可能导致不可预期的问题。
  2. 部分得分的实现不够灵活

    • 对于填空题和选择题,目前的部分得分规则是固定的(填空题一律得一半分,选择题按比例得分),缺乏可配置性。如果题目对部分正确的得分有特殊要求,可能需要修改代码。
  3. 忽略了非法输入的处理

    • 没有对 studentAnswerstandardAnswer 的异常情况(如空字符串或空值)进行校验,可能导致运行时错误或不一致行为。
    • 没有对输入格式(如空格、大小写等)进行全面规范化处理。
  4. 忽略了 isDeleted 的使用

    • 基类中定义了 isDeleted 属性,但在子类和逻辑中并未使用。如果某个题目被删除,这一属性并不会影响到评分逻辑。
    • 可能需要一个统一的机制判断是否允许对 isDeleted = true 的题目评分。
  5. 满分分值的处理方式不统一

    • 所有题型都定义了 fullScore 属性,但它是重复的,可考虑将 fullScore 提取到 BaseQuestion 中以减少冗余。
    • 如果将来某些题型需要动态调整满分,现有设计会导致子类冗余代码。
  6. 评分逻辑的复杂度增加风险

    • 选择题中,Arrays.asList(correctChoices).contains(choice.trim()) 对每个学生选项进行线性搜索,效率较低。当选项数量较大时,可能对性能产生不良影响。
    • 更高效的实现可以考虑使用 Set 存储正确选项,减少查找时间复杂度。
  7. 依赖标准答案的格式

    • 标准答案的格式直接影响程序逻辑,例如:
      • 填空题的多个标准答案依赖 分隔。
      • 选择题的多个选项依赖空格分隔。
    • 如果实际使用中标准答案的格式不统一,需要额外的预处理步骤。

采坑心得

采坑点

  1. 正则表达式解析问题

    • 不同题型的正则规则复杂且容易出错,尤其在处理学生答案中嵌套特殊字符时,容易导致解析失败。
    • 解决方法:需要更多的边界测试用例,并对正则模式进行容错优化。
  2. 部分正确逻辑的边界处理

    • 填空题和选择题的部分正确性判断逻辑中,未考虑答案集合的顺序问题。例如:
      • 选择题标准答案为"A B",学生答案为"B A"时,应计为正确。
    • 解决方法:在比较答案集合时统一使用Set存储和比较。
  3. 试卷总分检查问题

    • 系统通过alertIfPaperScoreNot100方法提醒试卷总分,但未提供自动修正方法,容易让用户误以为系统存在缺陷。
    • 解决方法:在生成提醒后自动补足或调整缺失分值。
  4. 代码复用性问题

    • 各题型的score方法逻辑重复,尤其是部分正确的处理可以提取到基类或工具类中统一实现。
    • 解决方法:抽象出一个评分辅助工具类。

改进建议

代码优化方向

  1. 答案相似度评分
    • 引入字符串相似度算法(如Levenshtein距离),让填空题支持更细致的评分规则。
  2. 正则优化
    • 针对多种数据格式,预定义更鲁棒的正则模式并进行单元测试。
  3. 部分正确逻辑提取
    • 在基类BaseQuestion中增加通用的部分正确判断方法,避免重复代码。
  4. 错误信息输出优化
    • 输出更清晰的错误信息,例如题目缺失或删除时,应同时标注题目内容或ID,便于排查。

****#家居强电电路模拟程序-1

1. 系统架构与功能

架构设计

  • 抽象基类:

    • Device: 所有设备的基类,定义了设备的核心功能接口,如processVoltage()getOutputValue()
    • ControlDeviceControlledDevice: 分别作为控制设备和受控设备的抽象基类,进一步细分了两种设备的行为特性。
  • 具体设备实现:

    • 控制设备:
      • SwitchDevice: 模拟开关,支持开关切换功能。
      • StepController: 模拟分档调速器,通过增减档位改变输出电压。
      • ContinuousController: 模拟连续调速器,通过设置连续参数改变输出电压。
    • 受控设备:
      • IncandescentLamp: 模拟白炽灯,输入电压不同会改变亮度。
      • DaylightLamp: 模拟日光灯,输入电压决定是否发光。
      • CeilingFan: 模拟吊扇,输入电压不同会改变风扇转速。
  • 辅助模块:

    • DeviceFactory
      提供设备的工厂方法,根据设备标识符动态创建不同类型的设备。
    • CommandProcessor
      处理控制命令,如开关操作、档位调整或参数设置。
    • CircuitSimulator
      模拟电路中电压的传递与设备输出值的计算逻辑。
    • Utils
      提供设备标识符与接口解析的工具方法。

功能清单

  1. 设备创建与初始化:
    通过读取连接关系列表,识别设备类型,并动态生成设备对象。

  2. 命令处理:
    接受用户输入的控制命令(如切换开关、调整参数),对设备状态进行修改。

  3. 电路模拟:
    根据电路连接关系,从电压源出发,逐步传递电压并计算设备的输入与输出。

  4. 设备输出收集:
    根据设备的优先级和编号排序,生成最终的设备输出值列表。

  5. 终端交互:
    接受用户输入的电路配置与命令,输出设备的最终状态。


2. 主要功能分析

功能模块分析

以下是系统核心功能模块的分析,包括设计思路和实现细节:

  1. 设备的分类与行为抽象

    • 设备分为控制设备和受控设备两大类,采用抽象类的方式对其特性进行了高层次的定义。
    • 各子类继承抽象类并实现特定行为,比如:
      • 开关设备的toggle()方法切换状态;
      • 白炽灯的computeOutput()通过输入电压计算亮度。
    • 这种设计方式体现了开放封闭原则(OCP),新设备类型只需扩展相应的类即可,无需修改其他部分代码。
  2. 设备优先级与输出排序

    • 优先级排序规则:
      • 开关 > 分档调速器 > 连续调速器 > 吊扇 > 白炽灯 > 日光灯
      • 使用getTypePriority()方法定义优先级,同时根据设备编号次序辅助排序。
    • 设计思路清晰,优先级的实现通过单独方法封装,便于扩展和维护。
  3. 电路仿真

    • 核心逻辑位于CircuitSimulator.simulate()中:
      • 模拟电压从电压源(VCC)开始的逐步传递;
      • 根据电路连接,动态调用控制设备的输出电压计算与受控设备的输入电压处理。
    • 模拟过程符合实际电路的逻辑,模块化设计使得不同设备类型的行为独立且可维护。
  4. 命令处理

    • CommandProcessor模块能够灵活解析命令,如:
      • 切换开关:#K1
      • 调整分档调速器:#F1+
      • 设置连续调速器参数:#L2:0.75
    • 每种命令的解析逻辑清晰,易于扩展新的控制方式。
  5. 用户交互

    • 系统通过标准输入读取用户输入的电路连接与命令,并以统一格式输出设备状态。
    • 输入与输出格式简洁明了,便于用户理解和操作。

下面是此程序的类图设计和顺序图设计
类图:

顺序图:

核心模块 4:电路模拟

代码:

class CircuitSimulator {
    public static void simulate(Map<String, Device> devices, List<String[]> connections) {
        double voltage = 220.0;
        for (String[] conn : connections) {
            String pinA = conn[0];
            String pinB = conn[1];

            String deviceA = Utils.extractDevice(pinA);
            String deviceB = Utils.extractDevice(pinB);

            String fromDevice;
            String toDevice;
            double inputVoltage = voltage;

            if (deviceA.equals("VCC")) {
                fromDevice = deviceA;
                toDevice = deviceB;
            } else if (deviceB.equals("VCC")) {
                fromDevice = deviceB;
                toDevice = deviceA;
            } else {
                fromDevice = deviceA;
                toDevice = deviceB;
            }

            if (!fromDevice.equals("VCC") && !fromDevice.equals("GND")) {
                Device device = devices.get(fromDevice);
                if (device instanceof ControlDevice) {
                    ControlDevice cd = (ControlDevice) device;
                    voltage = cd.getOutputVoltage(inputVoltage);
                }
            }

            if (!toDevice.equals("GND") && !toDevice.equals("VCC")) {
                Device device = devices.get(toDevice);
                if (device instanceof ControlledDevice) {
                    ControlledDevice ctl = (ControlledDevice) device;
                    ctl.processVoltage(voltage);
                    voltage = 0.0;
                }
            }
        }
    }
}

分析:

  • 模拟电路的电压传播:
    • 如果设备是控制设备(ControlDevice),先计算输出电压并传递。
    • 如果设备是受控设备(ControlledDevice),接收电压并计算自身状态。
  • 通过 connections 遍历电路连接关系,逐步完成电压的流动模拟。
  1. 核心逻辑

    • 按连接顺序遍历设备。
    • 电压从 VCC 开始传递,经过设备后可能会被修改。
    • 目标设备处理接收到的电压,模拟设备的电气行为。
  2. 关键类

    • Device:基类,表示一个通用设备。
    • ControlDevice:控制设备,可以根据输入电压计算输出电压。
    • ControlledDevice:被控设备,可以响应输入电压并处理其行为。
  3. 作用

    • 模拟了电压在电路中流动的过程,包括传递、调整和消耗。
    • 为进一步的电路模拟(如信号分析或功率计算)提供基础。

优点

1. 模块化设计

  • 使用了抽象基类(如 DeviceControlDevice),将设备功能分层抽象,提高了代码的清晰性和复用性。
  • 子类(如 SwitchDeviceStepController)继承并实现了抽象方法,符合 面向对象设计 中的 里氏替换原则,代码结构清晰且易于维护。

2. 良好的扩展性

  • 新增设备类型时,只需要继承 Device 或其派生类即可,符合 开闭原则
  • DeviceFactory 的工厂模式使用了 switch-case 处理设备类型,便于扩展更多设备。
  • Utils 类封装了公共逻辑,减轻了主程序的负担。

3. 完整性和功能性

  • 处理了多种设备类型(开关、调速器、灯、吊扇等),并实现了对应的特性逻辑。
  • 包含设备的初始化、命令处理、电路模拟和结果输出的完整流程,展示了一个小型 电路仿真系统 的设计思路。
  • 输出按优先级排序,逻辑清晰。

4. 代码规范性

  • 遵循 Java 命名规范,变量和方法名直观,便于理解。
  • 合理使用 MapList 等集合类,简化数据操作。

缺点和改进建议

1. 代码复用性有限

  • 问题:部分设备的实现逻辑有重复,比如 CeilingFanIncandescentLamp 的亮度和速度计算中存在类似的公式和条件判断。
  • 改进建议
    • 抽取公共计算逻辑到基类或工具类中,例如电压与输出值的映射可以提取为一个公共方法。

2. 硬编码问题

  • 问题:工厂方法中设备类型与优先级的映射硬编码在代码中,扩展设备类型时需要修改多个地方。
  • 改进建议
    • 使用配置文件或枚举(enum)来管理设备类型和优先级。例如:
      public enum DeviceType {
          SWITCH(1), STEP_CONTROLLER(2), CONTINUOUS_CONTROLLER(3), ... ;
          private final int priority;
          DeviceType(int priority) {
              this.priority = priority;
          }
          public int getPriority() {
              return priority;
          }
      }
      

3. 工厂模式不够灵活

  • 问题DeviceFactory 中的 createDevice 方法只支持单字符类型标识符,扩展到更复杂的设备命名时可能不适用。
  • 改进建议
    • 改用反射机制,根据设备类名动态生成对象。这样可以避免硬编码,进一步提高扩展性。

4. 耦合度较高

  • 问题:设备之间通过 CircuitSimulator 的电压传播进行交互,但没有解耦的机制(例如观察者模式)。
  • 改进建议
    • 引入 观察者模式 或事件驱动机制,允许设备之间通过事件通信而非直接依赖。

采坑心得

问题总结

  1. 电压传播逻辑不完善

    • 问题:CircuitSimulator 假设每个控制设备的输出电压只对下一个设备有效,缺乏分支传播支持。
    • 解决:可以通过递归模拟每条路径上的电压变化。
  2. 命令处理边界条件

    • 问题:连续调速器 (#L) 的参数未严格检查格式,可能出现非法输入导致异常。
    • 解决:在解析时添加输入校验。
  3. 设备创建与优先级排序冲突

    • 问题:当设备类型相同时,编号的解析存在潜在错误,如 Integer.parseInt 在无效输入下会抛异常。
    • 解决:加强对设备编号的合法性校验。

测试与验证

通过以下测试验证代码的正确性:

  1. 基本功能:输入连接 [K1-L1] [L1-B1] 和命令 #K1,模拟电路后验证白炽灯亮度变化。
  2. 复杂连接:多分支电路,如 [VCC-K1] [K1-F1] [F1-D1] [F1-B1],验证不同设备的行为。
  3. 异常输入:测试非法命令格式(如 #L1-1.5.0)和不合法连接(如 VCC-B1 未接控制设备)。

测试结果显示基本功能正常,但在复杂分支电路下需要优化逻辑。


家居强电电路模拟程序-2

本题目是一个面向对象编程 (OOP) 设计和实现的综合性实验,考察了设计模式、继承、多态、抽象类等高级特性在电路设备模拟场景中的应用。题目集难度偏高,涵盖了抽象类和接口设计、设备类型建模、电路仿真逻辑和命令解析,考验了代码架构设计与实现能力。

题目亮点包括:

  • 多样化设备类型:涵盖开关设备、调速设备、灯具、风扇等;
  • 复杂的电路模型:支持串联、并联电路;
  • 动态命令解析:允许对设备进行状态调整,反映现实中电路控制的特点。

难度上,该题目需要全面考虑类的设计和电路整体模拟的逻辑,以及边界条件的处理,如节点电压的传播、电阻的计算、电路优先级排序等。


1.设计与分析

本题的核心设计逻辑如下:

  1. 设备建模

    • 抽象类 Device 定义所有设备的通用接口,具体设备通过继承实现功能。
    • 设备分为两大类:
      • 控制设备 (ControlDevice):包括开关、分档调速器和连续调速器,主要用于调节电压。
      • 受控设备 (ControlledDevice):包括白炽灯、日光灯、吊扇和落地扇,主要根据电压计算输出值。
    • 设备类型通过优先级 (getTypePriority) 排序,控制设备优先处理。
  2. 电路结构设计

    • 电路分为串联和并联:
      • SerialCircuit 按顺序传递电压,逐步计算电压的变化。
      • ParallelCircuit 分析每条路径的总电阻,按并联规则分配电压。
    • 电路的输入、输出节点通过连接关系描述,输入电压来源于固定节点(如 VCC)。
  3. 模拟逻辑

    • 电压传播:基于输入电压,从串联电路的起点逐步向终点传递电压。
    • 电阻计算:控制电压降,根据电阻比例分配电压。
    • 电路优先处理:并联电路先于串联电路处理,确保节点电压一致。
  4. 命令解析

    • 支持动态调整设备状态,包括开关切换、调速档位调节和连续调速参数设置。
    • 解析命令格式,自动调用设备方法完成状态更新。

2. 主要功能分析

本题目主要实现了一个动态电路模拟系统,核心功能围绕设备建模、电路连接、电压传播及命令控制展开。以下是主要功能的详细分析:


1. 设备建模

通过面向对象编程设计,实现不同设备的抽象建模,统一设备行为接口,支持设备的多态化处理。

实现特点

  • 设备分为两大类:ControlDeviceControlledDevice
    • 控制设备:如开关 (SwitchDevice)、分档调速器 (StepController)、连续调速器 (ContinuousController) 等,负责调节电压的传递。
    • 受控设备:如白炽灯 (IncandescentLamp)、日光灯 (DaylightLamp)、吊扇 (CeilingFan)、落地扇 (FloorFan) 等,根据输入电压计算输出值。
  • 每个设备实现以下核心功能:
    • 状态管理:如开关的状态(开或关)、调速器的档位。
    • 电压处理:通过 processVoltage 方法调整输入电压,并输出对应的设备状态(如亮度或转速)。
    • 优先级定义:通过 getTypePriority 方法设置不同设备的处理优先级。

效果

  • 设备模型易于扩展:新增设备只需继承 Device 抽象类并实现对应方法。
  • 提供设备状态的动态调整能力。

2. 电路连接与建模

电路模型分为串联 (SerialCircuit) 和并联 (ParallelCircuit) 两种,通过连接关系模拟现实中的电路拓扑结构。

核心功能

  • 串联电路
    • 节点按顺序连接,电压逐步传播到各个设备。
    • 每个设备根据输入电压计算输出电压,传递至下一个节点。
  • 并联电路
    • 并联路径电压相同,但每条路径分配不同的电流。
    • 自动计算并联路径的等效电阻和总电压,统一输出。

实现逻辑

  • 电路连接关系通过 connections 列表描述,节点间的关系直接影响电压传播路径。
  • 每个电路实现 getInputgetOutput 方法,统一抽象输入输出端口。

效果

  • 支持复杂电路结构:通过组合串联和并联电路,可以实现各种电路拓扑。
  • 电路模型的动态模拟:电路状态随设备状态变化实时更新。

3. 电压传播与仿真

通过模拟电路的电压传播过程,计算所有设备的最终状态(如亮度或转速)。

功能实现

  1. 节点电压初始化

    • VCC 默认电压为 220V,GND 电压为 0V。
    • 其他节点根据电路和设备的连接关系动态计算电压。
  2. 电压传播逻辑

    • 按优先级处理并联电路,再处理串联电路。
    • 电压从输入节点逐步传递到输出节点,控制设备根据其逻辑调整电压,受控设备根据输入电压计算输出值。
  3. 电阻计算

    • 串联电路:累加路径上的设备电阻。
    • 并联电路:计算等效电阻,根据电流分配规则分压。

效果

  • 电压传播准确反映设备和电路状态的变化。
  • 模拟结果动态响应设备调整(如开关切换、调速档位调整)。

4. 动态命令控制

支持通过命令对设备进行动态调整,实时改变电路状态。

功能特点

  • 开关切换
    • #K1 切换开关 K1 的状态(开/关)。
    • 状态影响电路电压传播路径。
  • 分档调速器调整
    • #F1+#F1- 增加或降低分档调速器 F1 的档位。
    • 调速器档位影响输出电压比例。
  • 连续调速器参数设置
    • #L1:0.75 设置连续调速器 L1 的输出比例为 75%。
    • 输出比例影响电压传递的强度。

实现逻辑

  • 命令解析器 CommandProcessor 根据命令类型调用对应设备的方法。
  • 调整设备状态后,重新模拟电路计算电压。

效果

  • 提供动态控制能力,模拟真实场景中设备的交互。
  • 支持实时查看调整结果,验证命令的效果。

5. 输出结果收集

将所有设备的最终状态按优先级输出,直观展示仿真结果。

功能实现

  • 排序规则
    • 设备按类型优先级从高到低排序。
    • 同类型设备按编号升序排列。
  • 输出格式
    • 格式为 @设备ID:状态值,如 @B1:100 表示白炽灯 B1 的亮度为 100。
  • 设备状态收集
    • 调用 getOutputValue 获取设备状态值,统一格式化输出。

效果

  • 清晰直观地展示电路仿真结果。
  • 输出顺序合理,便于用户快速定位设备状态。

下面是此程序的类图设计和顺序图设计
类图:

顺序图:

设备初始化

代码位置

public static Map<String, Device> initializeDevices(List<String[]> connections) {
    Map<String, Device> devices = new HashMap<>();
    for (String[] conn : connections) {
        String deviceA = Utils.extractDevice(conn[0]);
        String deviceB = Utils.extractDevice(conn[1]);

        if (!deviceA.equals("VCC") && !deviceA.equals("GND") && !deviceA.equals("IN") && !deviceA.equals("OUT") && !devices.containsKey(deviceA)) {
            Device device = createDevice(deviceA);
            if (device != null) {
                devices.put(deviceA, device);
            }
        }
        if (!deviceB.equals("VCC") && !deviceB.equals("GND") && !deviceB.equals("IN") && !deviceB.equals("OUT") && !devices.containsKey(deviceB)) {
            Device device = createDevice(deviceB);
            if (device != null) {
                devices.put(deviceB, device);
            }
        }
    }
    return devices;
}

功能分析

  1. 设备解析:从连接的端点(如 K1-1)提取设备 ID(如 K1)。
  2. 设备创建:根据设备类型 ID(如 K, F, B)调用 createDevice 工厂方法生成对应设备对象。
  3. 设备去重:确保同一设备不会被多次创建。

设备工厂方法

private static Device createDevice(String deviceId) {
    char type = deviceId.charAt(0);
    switch (type) {
        case 'K': return new SwitchDevice(deviceId);
        case 'F': return new StepController(deviceId);
        case 'L': return new ContinuousController(deviceId);
        case 'B': return new IncandescentLamp(deviceId, 10);
        case 'R': return new DaylightLamp(deviceId);
        case 'D': return new CeilingFan(deviceId);
        case 'A': return new FloorFan(deviceId);
        default: return null;
    }
}

控制命令处理

代码位置

public static void processCommands(Map<String, Device> devices, List<String> commands) {
    for (String cmd : commands) {
        if (cmd.startsWith("#K")) { // 开关命令
            String deviceId = cmd.substring(1);
            SwitchDevice sw = (SwitchDevice) devices.get(deviceId);
            if (sw != null) {
                sw.toggle();
            }
        } else if (cmd.startsWith("#F")) { // 分档调速器命令
            // 解析命令并调整档位
        } else if (cmd.startsWith("#L")) { // 连续调速器命令
            // 解析命令并调整参数
        }
    }
}

功能分析

  1. 命令解析
    • #K<id>: 切换开关状态。
    • #F<id>+: 增加分档调速器档位。
    • #L<id>:value: 设置连续调速器的档位参数。
  2. 设备操作
    • 根据命令对设备状态进行修改。

电路模拟

代码位置

public void simulate() {
    // 初始化节点电压
    Map<String, Double> nodeVoltages = new HashMap<>();
    nodeVoltages.put("VCC", 220.0);
    nodeVoltages.put("GND", 0.0);

    // 处理并联电路
    for (Circuit circuit : circuitList) {
        if (circuit instanceof ParallelCircuit) {
            processParallelCircuit((ParallelCircuit) circuit, nodeVoltages);
        }
    }

    // 处理串联电路
    for (Circuit circuit : circuitList) {
        if (circuit instanceof SerialCircuit) {
            processSerialCircuit((SerialCircuit) circuit, nodeVoltages);
        }
    }

    // 最终电压处理
    for (Circuit circuit : circuitList) {
        if (circuit instanceof SerialCircuit) {
            SerialCircuit sc = (SerialCircuit) circuit;
            String lastPin = sc.getOutput();
            if (!lastPin.equals("OUT") && !lastPin.equals("GND")) {
                double voltage = nodeVoltages.getOrDefault(lastPin, 0.0);
                Device device = devices.get(Utils.extractDevice(lastPin));
                if (device instanceof ControlledDevice) {
                    ((ControlledDevice) device).processVoltage(voltage);
                }
            }
        }
    }
}

功能分析

  1. 初始化节点电压
    • VCC 为 220V,GND 为 0V。
    • 未指定的节点默认为接地(0V)。
  2. 并联电路处理
    • 根据路径电阻计算等效电阻和输出电压。
  3. 串联电路处理
    • 遍历串联路径,逐级传递输入电压并计算每个设备的输出电压。
  4. 设备最终电压更新
    • 受控设备根据最终电压计算输出值。

优点

  1. 模块化设计

    • 各类设备(如开关、分档调速器、吊扇等)通过继承抽象基类 Device 实现了良好的模块化设计。
    • 控制设备和受控设备分别定义了不同的抽象基类,进一步细化了设计,提高了代码的可扩展性和复用性。
    • 电路部分(串联、并联)也有对应的抽象类 Circuit,逻辑清晰,便于扩展新的电路类型。
  2. 面向对象思想

    • 利用了多态,通过 Device 的抽象接口 processVoltagegetOutputValue 实现了设备行为的动态绑定,增强了系统的灵活性。
    • 不同设备根据其类型实现了各自的电压处理逻辑,满足“开闭原则”(对扩展开放,对修改封闭)。
  3. 支持复杂电路模拟

    • 支持串联和并联电路的组合,能够对复杂的电路场景进行建模和仿真。
    • 电路模拟中考虑了电压分配、电阻计算等物理特性,逻辑严谨。
  4. 清晰的输入输出设计

    • 输入格式明确,支持设备连接、串联和并联电路定义,以及命令控制。
    • 输出设备按优先级排序,统一格式输出,方便使用者理解。
  5. 良好的扩展性

    • 新增设备类型(例如新增一种灯)或电路类型(例如桥式电路)时,只需继承相关抽象类并实现逻辑,无需修改现有代码。
  6. 模拟逻辑合理

    • 处理了串联电路中的电压分布和并联电路中的电流分布。
    • 对设备输入电压和输出值的计算贴合物理现实,例如白炽灯的亮度线性变化,吊扇的速度变化等。

缺点

  1. 并联电路电压逻辑不完整

    • 并联电路的处理仅假设所有支路的输入电压相同,但未考虑支路之间的电阻分布对电流和电压的影响,实际物理意义可能存在偏差。
  2. 设备连接依赖硬编码约定

    • 设备连接逻辑较为依赖固定格式(如 [K1-1 K2-2]),一旦输入格式不符,则容易导致解析失败。需要更健壮的输入解析方案。
    • 并联电路的实现中,假设所有支路输出引脚一致,没有进行验证,可能在复杂情况下引发错误。
  3. 节点电压初始化过于简化

    • 所有未定义的节点默认电压为 0.0,可能导致非预期行为。应结合连接信息动态计算未定义节点的电压。
  4. 代码复杂性较高

    • 由于支持了较多的功能和扩展,代码显得较为复杂。部分方法(如 processSerialCircuitprocessParallelCircuit)逻辑过于冗长,阅读和维护成本较高。
    • 设备和电路的创建逻辑散落在多个类中(如 DeviceFactoryCircuitSimulator),分工有些模糊。
  5. 缺少单元测试支持

    • 当前代码完全依赖用户输入进行验证,缺少单元测试代码,难以确保各模块的正确性和鲁棒性。
  6. 性能优化空间

    • 并联电路的等效电阻计算是通过循环累积实现的,对于复杂并联场景可能效率较低。
    • 串联电路中,重复遍历节点和设备列表,影响执行效率。
  7. 异常处理缺乏

    • 对于设备类型或连接格式的错误缺乏有效的异常处理(如非法输入设备类型)。
    • 在设备控制命令(如 #Lx:y)解析时,如果参数错误会直接抛出异常,导致程序终止。
  8. 设备间相互依赖性未完全处理

    • 设备之间的复杂交互逻辑(如同一节点多个设备)未完全考虑,可能出现难以预料的边界情况。

题目集总结

1. 面向对象设计的体会

通过三次题目集的开发,深刻体会到面向对象设计的重要性。以下是几点主要收获:

  • 抽象与多态的威力
    • 在答题判题程序和电路模拟程序中,通过抽象类和接口对核心功能进行统一设计,不同子类实现自己的逻辑,增强了代码的灵活性和扩展性。比如,设备的抽象接口 processVoltage() 让新增设备的行为逻辑非常清晰且独立。
    • 多态避免了冗余代码,提高了程序的可维护性,符合“开闭原则”(对扩展开放,对修改关闭)。
  • 职责划分的意义
    • 每个模块职责明确,像答题判题程序的 BaseQuestionScoringService,以及电路模拟程序的 ControlDeviceCircuitSimulator,这种分层设计使得功能扩展时互不干扰,降低了代码的耦合度。
  • 设计的平衡
    • 学会了避免过度设计。初期可能会为了追求扩展性设计很多冗余接口和复杂结构,但随着实践深入,逐渐意识到根据实际需求设计才是高效的。

2. 系统化思维的提升

三次题目集的开发从简单到复杂,逐步培养了系统化思维的能力:

  • 整体框架与细节兼顾
    • 在设计阶段,更加注重从整体功能入手,先明确每个模块的职责,再细化每个模块的实现。比如,在电路模拟程序中,先确定了电路整体的输入、输出和设备连接关系,再细化到每种设备的行为。
  • 逐步完善功能
    • 通过分阶段实现和迭代开发,避免了设计过早陷入复杂场景。比如,从单纯的串联电路模拟到加入并联逻辑,系统架构能够逐步扩展而不需要大幅改动已有逻辑。
  • 动态交互的设计
    • 随着系统功能复杂化,动态命令解析和用户交互的设计显得尤为重要。这在家居强电电路模拟中体现得尤为明显,通过解析器让用户输入的命令能够动态调整设备状态,增强了系统的灵活性。

3. 面对复杂问题的解决能力

从简单的评分逻辑到复杂的电路仿真,开发过程中的难度逐渐升级,遇到的难点也越来越多。这些挑战让我学会了一些解决复杂问题的方法:

  • 拆分问题,化繁为简
    • 在面对电路模拟的复杂逻辑时,先从简单的串联电路入手,将并联的难点暂时搁置。通过逐步攻克简单问题,建立对系统整体的理解后,再逐步增加复杂性。
  • 调试与验证的重要性
    • 每次功能实现后,都会通过大量测试用例验证功能的正确性。比如,对电路模拟程序,设计了多种复杂的连接关系和异常输入进行测试,发现了许多潜在的边界问题。
  • 边界条件与异常处理
    • 实现复杂系统时,边界条件和异常输入是经常容易忽略的问题。在电路模拟中,如果节点电压未初始化或设备连接格式不对,可能导致整个仿真逻辑崩溃。通过这些案例,我逐渐学会为代码添加更多的校验和保护措施。

4. 学会权衡复杂性与可维护性

  • 在程序设计中,复杂性和可维护性往往是两个对立面:
    • 追求功能的丰富性:在家居强电电路模拟程序-2中,并联电路的加入显著增加了逻辑复杂度,同时也让代码难以维护。
    • 保持系统的简洁性:通过模块化设计和合理分层,尽量避免功能堆砌造成的代码难读问题。
  • 通过这三次开发,学会了合理规划需求的优先级,优先实现关键功能,同时为未来的功能扩展留出空间。

5. 工程化能力的提升

  • 代码复用与优化:逐渐意识到高质量代码不仅是功能实现,还需要追求代码的简洁、可读性和复用性。在答题判题程序中,通过抽取通用逻辑到工具类减少了重复代码。
  • 单元测试与验证:每次新功能实现后都会编写测试用例,确保代码在边界条件和异常情况下能正常运行。这让我养成了编写单元测试的习惯。
  • 文档与注释:随着系统复杂度的增加,文档和注释变得尤为重要。通过为每个类和方法添加注释,以及撰写系统设计文档,帮助自己更好地理解代码。

6. 未来的改进方向

尽管在三次题目集中取得了一定成果,但仍有许多可以改进的地方:

  1. 提高模拟深度:在家居强电电路模拟中,电路的物理模拟(如电流、电阻)仍不够完善,需要加入更真实的物理规则。
  2. 提升代码性能:电路模拟中部分方法(如并联电路的电阻计算)性能较低,可以优化算法以支持更大规模的电路。

总结

这三次题目集的开发让我对面向对象设计、系统架构、复杂逻辑实现和工程化能力有了更深入的理解。从简单的评分逻辑到复杂的电路仿真,不断的学习和实践让我逐渐掌握了解决问题的方法,提升了编程能力和设计水平。未来,我希望在代码优化、物理模拟深度和用户体验设计上继续努力,不断完善自己的技术能力。

posted @ 2024-11-23 19:59  flysusdjd  阅读(36)  评论(0)    收藏  举报