面向对象程序设计——第二章作业总结

前言

两次编程作业均围绕 “数字电路逻辑 + 编程实现” 核心,知识点呈从基础到进阶、从单一到复杂的递进特征,覆盖 “字符串处理、数据结构、逻辑运算、元件规则、输出控制” 五大核心维度,让我们不断对我们的代码进行修改和完善,而我们的课堂检测则是检验我们对于java编程基础知识的掌握,下面是我对我所编写的两次程序设计以及课堂检测的分析。

题目中的知识点

在一次作业中:本次题目要求我们实现基础元件名解析、简单引脚解析以及连接信息 / INPUT 行基础拆分,这是考察我们对于字符串的解析与处理,此外,本次题目还涉及了我们的数据结构设计:字典存储:引脚信号(0/1)、元件元信息(类型 / 输入数 / 编号)、列表:元件排序 / 遍历和单输出元件的信号映射,并且在本次作业中还要求我们实现了基础布尔运算和输入有效性检查。

在第二次作业中:本次作业是在第一次作业的基础上进行了优化,它新增了复杂元件名解析,还要兼容第一次的基础解析逻辑,需适配新旧元件格式。此外,本次作业还进行了字典扩展:新增 “引脚类型” 字段、多输出元件信号存储(如译码器 8 个输出、分配器 8 个输出)、新增 “无效状态” 标记(高阻态、译码器无效、分配器非选中输出)、保持列表排序逻辑,适配 9 类元件的排序优先级。最主要的是它新增了组合电路逻辑,添加了三态门、译码器等元件,对于第一次作业而言,实现更加的困难。

在课堂检测中:本次课堂检测是为了考验我们对于Java基础知识的学习情况,题目从多个角度考察我们对于基础知识点的掌握,本次检测涵盖了书中的几乎全部知识点,考察面较为广泛。

难度:

两次作业对于我们而言,难度呈阶梯式提升,核心差异在于 “元件复杂度、规则多样性、数据处理维度” 的增加。第一次作业中的核心难点在于基础元件名 / 引脚的字符串精准拆分、多输入与 / 或门的运算实现以及元件排序与有效输出筛选,但是由于这是第一次作业,所以难度相对来说更加简单,因为它仅单输出元件,无控制引脚,输入引脚编号规则简单,输出格式单一并且无无效状态。第二次实验相对于第一次实验而言更加困难,它的核心难点在于复杂引脚规则解析,新增元件的逻辑规则,多输出元件的无效状态标记以及多样化输出格式的适配。相较于第一次而言元件从 “单输入 / 单输出、无控制” 升级为 “多输入 / 多输出、带控制引脚”,逻辑从 “基础布尔运算” 升级为 “控制条件 + 编码映射 + 多输出,数据从 “仅 0/1” 扩展为 “0/1 + 无效 -,输出从 “统一格式” 变为 “按元件定制格式”,需大量条件分支。对于课堂检测而言,这次检验中的题目虽然量很多,但是难度都普遍不高,主要都是对于我们基础知识的考查,相对于题目难度而言,它更加考察我们的细心以及对于书本知识的掌握。

题量:

两次作业均为单道综合编程题,但第二次在第一次基础上新增 4 类元件及配套规则,工作量显著提升,代码量翻倍,模块从 “基础 5 个” 扩展为 “进阶 9 个”,核心工作量向 “解析” 和 “逻辑运算” 倾斜。对于课堂检测,这次检测的题量非常多,包含了单选题,多选题,判断题以及填空题,总分有230多分,题目也非常多,虽然难度普遍较低,但是数量并不少。

设计与分析

第一次作业:

题目:数字电路是一种处理离散信号的电子电路。与处理连续变化信号(如声音、温度)的模拟电路不同,数字电路只识别和运算两种基本状态:高电平(通常表示为“1”) 和 低电平(通常表示为“0”)。这正好与二进制数制系统相对应,使得数字电路成为所有计算机和数字系统的物理实现基础,请编程实现数字电路模拟程序。电路中包含与门、或门、非门、异或门、同或门五种元件。元件信息:用A、O、N、X、Y 分别用作与门、或门、非门、异或门、同或门五种元件的元件标识符。电路中的每个与门、或门用“标识符(输入引脚数)+编号”作为其元件名。电路中的每个非门、异或门、同或门用“标识符+编号”作为其元件名。引脚信息由“元件名-引脚号”构成,电路的输入格式:

INPUT:英文空格+输入1+”-”+输入信号1+英文空格+输入2+....+输入n+”-”+输入信号n

引脚的连接信息格式:

[+输出引脚+英文空格+输入引脚1+。。。。+英文空格+输入引脚+]

按照与门、或门、非门、异或门、同或门的顺序依次输出所有元件的输出引脚电平。同类元件按编号从小到大的顺序排序。

通过题目可以看出本次作业包含了多个类,类图如下:

image

 使用SouceMonitor对第一次代码进行静态分析,情况如下:

image

优点: 

模块划分清晰:输入、连接、模拟、输出等功能拆分到不同方法,可读性与维护性较好。

内聚性高:内部类封装了数据实体,避免了全局变量的滥用。

逻辑正确:信号传递采用广度优先遍历,符合数字电路中信号的传播顺序;元件输出计算严格遵循逻辑门规则。

不足:

注释不足:仅少量代码有注释,关键逻辑(如simulate的信号传递)无说明,后期维护成本高。

异常处理缺失:

-解析元件名 / 输入时,若格式错误(如A(abc)1),Integer.parseInt会抛出NumberFormatException

-引脚编号越界(如输入引脚号大于元件输入数)会抛出ArrayIndexOutOfBoundsException。代码无异常捕获,健壮性差。

扩展性差:仅支持 5 种基础逻辑门,若要添加三态门、译码器等新元件,需修改parseComponentNamecalculateGateOutput等多个方法,违反 “开闭原则”。

 

第二次作业:

题目:数字电路是一种处理离散信号的电子电路。与处理连续变化信号(如声音、温度)的模拟电路不同,
数字电路只识别和运算两种基本状态:高电平(通常表示为“1”) 和 低电平(通常表示为“0”)。
这正好与二进制数制系统相对应,使得数字电路成为所有计算机和数字系统的物理实现基础。
请编程实现数字电路模拟程序。
以下内容中,首行用#号标注的为本次新增的题目要求,其余内容与“数字电路模拟程序-1”相同。

电路中包含与门、或门、非门、异或门、同或门、三态门、译码器、数据选择器、数据分配器九种元件。用A、O、N、X、Y、S 、M、Z、F分别用作与门、或门、非门、异或门、同或门、三态门、译码器、数据选择器、数据分配器九种元件的元件标识符。引脚信息由“元件名-引脚号”构成。#含控制引脚的元件如本次添加的所有元件,按控制-输入-输出的顺序排序, 每种类型的引脚按编号从小到大的顺序排序, 例如3-8线译码器M(3)1包含3个输入引脚、3个控制引脚、8个输出引脚, M(3)1-0/1/2对应控制引脚S1/S2/S3, M(3)1-3/4/5对应输入引脚A0/A1/A2, M(3)1-6/7/8/9/10/11/12/13对应输出引脚Y0\~Y7。 又如三态门的三个引脚,0号引脚为控制端、1号引脚为输入端、2号引脚为输出端。

引脚的连接信息格式:[输出引脚+英文空格+输入引脚1+。。。。+英文空格+输入引脚]

按照与门、或门、非门、异或门、同或门、三态门、译码器、数据选择器、数据分配器的顺序依次输出所有元件的输出引脚电平。
同类元件按编号从小到大的顺序排序。

在这次作业中要求设计多个类,具体设计类图如下:

image

使用SouceMonitor对第二次代码进行静态分析,情况如下:

image

优点: 

高扩展性:基于Component抽象类的设计,新增电路元件只需继承并实现抽象方法,无需修改Main的核心逻辑,符合 “开闭原则”。

单一职责:

每个元件子类仅负责对应电路的逻辑(如Demultiplexer只处理分配器规则);

Main仅负责统筹数据与流程,职责边界清晰。

高效数据管理:HashMap存储元件、连接关系、引脚电平(O (1) 查找效率);用Queue实现信号的广度优先传播(保证信号按顺序传递)。

输出格式适配:每个元件的getOutputString方法适配题目要求的差异化输出(如译码器输出 “元件:索引”、分配器输出 “元件:--0-”),无需额外格式转换逻辑。

不足:

异常处理缺失:解析元件名、引脚编号时,若遇到非法格式(如A(abc)1),Integer.parseInt会抛出NumberFormatException;引脚编号越界也会触发IndexOutOfBoundsException,但代码未做捕获处理,健壮性不足。

注释覆盖不足:仅元件类型有少量注释,核心流程(如simulate的信号传播逻辑)无详细说明,后期维护成本较高。

引脚规则硬编码:元件的引脚命名(如TriStateGatename+"-0")是硬编码,若引脚规则变化(如控制引脚编号调整),需修改多个子类。

内部类的复用限制:所有元件类都是Main的内部类,若需在外部代码中复用这些元件逻辑,会受到访问权限的限制。

 
两次代码呈现从 “过程式编程” 到 “面向对象编程” 的典型演进:
  1. 架构层面:从 “无抽象、硬编码” 升级为 “抽象基类 + 子类实现”,解耦通用逻辑与差异化逻辑;
  2. 功能层面:从 “基础门模拟” 扩展为 “全品类组合电路模拟”,覆盖控制引脚、多输入输出、无效状态等复杂规则;
  3. 设计层面:从 “违反开闭原则” 升级为 “符合面向对象核心原则”,扩展性、可维护性大幅提升;
  4. 细节层面:从 “单一输出格式” 升级为 “差异化输出格式”,从 “简单信号传播” 升级为 “适配多元件的信号传播逻辑”。

课堂检测

本次课堂检测的准确率在73%左右,通过本次检测也可以发现自己对于哪些知识点还没有掌握,通过部分错误也可以总结自己对于课本的知识点的学习还有哪些欠缺。

采坑心得:

在本次完成作业的过程中我也遇到了许多问题,首先是在第一次作业中,代码仅支持 5 类基础门(与 / 或 / 非 / 异或 / 同或),代码行数约 200 行;新增译码器时,需修改parseComponentName(新增正则解析)、calculateGateOutput(新增 switch 分支)、getResults(新增排序类型)3 个核心方法,代码改动量约 50 行,提交 3 次均因逻辑耦合导致基础门功能异常(如与门输出错误)。类设计缺陷:Component为普通数据类,仅存储 “类型 / 编号 / 输入数 / 输入引脚值”,所有计算逻辑集中在calculateGateOutput的 switch 块(约 40 行),违反 “单一职责原则”,修改译码器逻辑时误改与门分支,导致基础用例失效。这次作业的流程为输入解析 → 连接解析 → 队列传播信号 → 硬编码计算基础门输出 → 输出结果,在计算输出环节与元件类型强耦合,新增元件必须修改此环节,破坏原有逻辑。在第二次作业中,抽象基类Component仅定义输出方法签名,未明确格式契约,子类getOutputString实现差异大,提交后输出格式错误。第二版译码器初始输出格式为M(3)1-6:0(引脚 + 值),但题目要求M(3)1:2(元件 + 输出 0 的索引),修改后又因分配器输出需包含 “-”(如F(2)1:--1-)遗漏,提交 2 次格式错误,类设计缺陷:抽象方法getOutputString仅返回 String,无格式常量 / 参数规范,子类实现完全依赖开发者记忆,易偏离题目要求。

而在课堂检测中也有许多问题,其中在多选题中错误题目相较于其他类型题目来说更多,有一半的题目都出现了错误,主要题目有:

1.接口和抽象类描述正确的有

A.抽象类没有构造函数
B.接口没有构造函数
C.抽象类不允许多继承
D.接口中的方法可以有方法体
对于该题目的分析如下:

A 选项(错误):抽象类本质还是类,拥有构造函数(供子类调用初始化),只是不能直接实例化。

B 选项(正确):接口不是类,不存在构造函数,无法实例化。

C 选项(正确):Java 中类(包括抽象类)仅支持单继承,接口才支持多实现 / 多继承。

D 选项(正确):Java 8 及以上版本中,接口允许定义default(默认方法)、static(静态方法),这类方法可以有方法体。

通过该题目可以发现自己对于接口以及抽象类的知识点还是存在部分问题,需要加强这部分的学习。

以该题目为例子,本次小测中的许多错误都是由于对于知识点的掌握还不够清晰,对于许多问题的答案还比较模糊,还有部分题目是由于自己审题时不够认真,导致部分题干没有考虑清楚,最后出现错误。

改进建议:

补充抽象基类的格式契约:

Component中定义统一格式常量,明确子类输出规则,减少格式错误

引入工厂模式管理元件创建:

新增ComponentFactory类,集中处理元件解析与异常,解耦Main类的创建逻辑

数值解析 / 引脚访问添加兜底逻辑

// 元件解析时的数值校验
private Component parseComponent(String name) {
    if (name.startsWith("A(")) {
        Pattern pattern = Pattern.compile("A\\((\\d+)\\)(\\d+)");
        Matcher matcher = pattern.matcher(name);
        if (matcher.find()) {
            int inputCount;
            int id;
            try {
                inputCount = Integer.parseInt(matcher.group(1));
                id = Integer.parseInt(matcher.group(2));
            } catch (NumberFormatException e) {
                return null; // 非法数值直接返回null,不终止程序
            }
            return new BasicGate(name, "A", id, inputCount);
        }
    }
    // ...
}

// 引脚访问的越界校验
@Override
void calculateOutputs(Map<String, Integer> pinValues, Queue<String> queue) {
    if (!allInputsReady(pinValues)) return;
    if (inputPins.size() != inputCount || inputPins.isEmpty()) {
        return; // 引脚数不匹配时直接返回,避免越界
    }
    // 原有计算逻辑...
}

自定义异常体系,分级处理错误

// 自定义异常:元件格式错误 class ComponentFormatException extends RuntimeException { public ComponentFormatException(String message) { super(message); } } // 自定义异常:引脚未就绪 class PinNotReadyException extends RuntimeException { public PinNotReadyException(String message) { super(message); } }

对于课堂检测而言,通过本次检测,我发现了自己对于部分知识点的掌握还是不够牢固,例如接口和抽象类的相关概念,JAVA中有效的注释说明、封装的相关概念等。
总结:
通过两次作业,我掌握了HashMap(O (1) 查找)、Queue(广度优先)在信号传播中的应用:第一版用数组存储输入引脚,查找效率 O (n);第二版用Map<String, Integer>存储引脚值,效率提升至 O (1),大规模电路模拟时响应更快,还理解了 “输入解析→逻辑计算→输出整理” 的通用程序流程,学会用队列保证信号按依赖顺序传播(避免先计算下游元件、后计算上游元件的逻辑错误)。
同时还理解了意识到 “异常处理 / 注释 / 格式契约” 的重要性:两次作业共提交 8 次,其中 5 次失败源于无异常处理、格式不统一,而非核心逻辑错误,工程化编码能大幅降低提交失败率。

posted @ 2025-12-14 19:22  whnd  阅读(5)  评论(0)    收藏  举报