第二次BLOG
(1)前言
这次BLOG针对两次大作业和一次测试,我会分析两次大作业的做法、设计、遇到的问题等等,针对测试检查基础知识。
(2)设计与分析
第一次大作业分析:


根据以上分析可以得出分析结果:
- Main.main() 方法过于复杂
• 复杂度高达 28(远高于平均复杂度 3.82)
• 包含 57 条语句
• 最大块深度达到 7
• 有 41 个方法调用
• 这是代码中最严重的问题,违反了单一职责原则 - Main.parseGate() 方法也过于复杂
• 复杂度 9
• 24 条语句
• 需要重构简化 - 代码注释率偏低
• 仅 6.2% 的行有注释
• 建议至少达到 20-30% 的注释率
以下是这次大作业类图:
![image]()
Main 类:
• 包含主要的控制逻辑
• 方法:
o parseGate(String)- 解析门电路
o compareGate(Gate, Gate)- 比较门电路
o getGateType(String)- 获取门类型
o main(String[])- 程序入口
o 构造函数
Gate 基类:
• 属性:
o ready(boolean) - 就绪状态
• 方法:
o toString()- 字符串表示
o compute()- 计算逻辑(应该是抽象方法)
o 构造函数
具体门类:
• 都继承自 Gate
• 每个类都有自己的:
o 构造函数
o compute()方法实现
下面是我对这一次作业的改进意见:
-
引入工厂模式
// 建议创建 GateFactory
class GateFactory {
public static Gate createGate(String type, int id, int inputCount) {
switch(type.toLowerCase()) {
case "xor": return new XorGate(id, inputCount);
case "xnor": return new XnorGate(id, inputCount);
// ... 其他类型
}
}
} -
重构 Main 类
移除 parseGate()和 getGateType()到专门的类
Main 只保留主流程控制 -
完善 Gate 基类
abstract class Gate {
protected boolean ready;
protected int id;
protected String type;public abstract void compute(); // 明确声明为抽象方法
// 添加通用方法
public boolean isReady() { return ready; }
public int getId() { return id; }
} -
添加比较器接口
interface GateComparator {
int compare(Gate g1, Gate g2);
}
第二次作业:


主要问题分析
- 高复杂度问题(严重)
• Main.parseComponent() 复杂度高达18(远超推荐值<10)
• Main.main() 复杂度14,也过高
• 最大复杂度18表明存在过度复杂的逻辑,可能需要重构 - 代码结构问题
• 方法过长:平均每个方法10.29个语句,部分方法过长
• 嵌套过深:最大块深度8层,平均2.30层,存在深层嵌套
• 分支语句占比30.8%,控制流较复杂 - 代码可读性问题
• 注释比例仅9.8%,远低于建议的20-30%
• 缺乏足够文档说明
![image]()
Component (抽象基类)
├── 基本门电路 (AndGate, OrGate, NotGate, XorGate, XnorGate)
├── 三态门 (TriStateGate)
├── 组合逻辑器件 (Multiplexer, Decoder, Demultiplexer)
└── Main (控制器/工厂类)
优点:
• ✅ 符合开闭原则:新增组件只需继承Component
• ✅ 统一的接口规范
• ✅ 模板方法模式确保执行流程一致性
2. 工厂模式应用
图中显示多个类有<
• Main类承担工厂角色,负责组件创建
• 符合单一职责原则:组件使用与创建分离
3. 继承层次清晰
逻辑门基础 (And/Or/Not) → 复杂门电路 (Xor/Xnor) → 组合器件 (Mux/Decoder)
• 层次结构合理,便于扩展
• 多态性得到充分利用
现存问题的根源:
- Main类过重(复杂度18)
o 原因:承担了parseComponent()和工厂创建双重职责
o 违反了单一职责原则 - 高复杂度方法
下面是我对这一次作业的改进意见:
阶段一:立即改进
// 1. 拆分Main类的职责
class ComponentFactory { // 专门负责创建
static Component create(String type, Map<String, Object> params)
}
class ComponentParser { // 专门负责解析
static Component parse(String input)
}
// 2. Main类只负责协调
class Main {
public static void main(String[] args) {
Component comp = ComponentParser.parse(input);
// ... 使用组件
}
}
阶段二:架构优化
// 1. 引入Builder模式
interface ComponentBuilder {
ComponentBuilder setInputs(Map<String, Integer> inputs);
ComponentBuilder setConfiguration(Map<String, Object> config);
Component build();
}
// 2. 添加配置类
class CircuitConfig {
private Map<String, Component> components;
private Map<String, Connection> connections;
// 支持从文件/字符串加载配置
}
阶段三:设计模式增强
// 1. 策略模式 - 不同的计算策略
interface ComputeStrategy {
Object compute(Map<String, Integer> inputs);
}
// 2. 访问者模式 - 支持电路分析
interface CircuitVisitor {
void visit(AndGate gate);
void visit(OrGate gate);
// ... 其他组件
}
本次测试分析:
Java中,静态方法只能访问静态的成员变量和静态的成员方法。
Java中,子类中所有的构造方法默认都会访问父类中空参数的构造方法。
Java中,接口中可以定义非抽象方法。
Java中,外部类不能用private修饰。
Java中,接口可以定义为抽象接口。例如:public abstract interface Inter{}
Java中,以下代码会抛出异常。
package kaoshi;
public class Demo_Exception {
public static void main(String[] args) {
System.out.println(1.0 / 0);
}
}
Java中,String是关键字。
Java中,主类的静态代码块优先于主方法(main方法)执行。
核心错误原因分析
- 绝对化思维
• 认为"只能"、"都会"、"不能"等绝对描述都是对的
• 实际上Java有很多特例和边界情况 - 忽略版本差异
• 特别是接口特性,Java 8是重要分水岭
• 不同版本JDK行为可能不同 - 概念混淆
• 把"可以"和"必须"混淆
• 把"语法允许"和"最佳实践"混淆
• 警惕绝对词:"只能"、"都会"、"所有"、"一定" → 通常有例外
• 考虑版本:特别是Java 8的特性变化
• 区分编译时/运行时:有些是编译错误,有些是运行时异常
• 动手验证:不确定就写个小程序测试
(3)采坑心得
一次次的"我懂了"和"我又错了"
在完成两次大作业和一次测试的过程中,我深刻体会到编程不仅是要让代码"能跑",更要让代码"优雅"。每一次的踩坑,都是一次宝贵的成长机会。
- "代码能跑就行"的陷阱
第一次大作业时,我抱着完成任务的心态,把所有逻辑都塞进Main.main()方法里。看着584行代码,我甚至还觉得有点自豪——"看我写了这么多!" 坑点体验:
// 曾经的"得意之作" - 一个近60行的main方法
public static void main(String[] args) {
// 读取文件
// 解析每一行
// 创建对象
// 处理输入
// 计算结果
// 输出结果
// ... 还有各种异常处理
// 当需要修改时:天啊,这里改一点,那边全崩了!
}
醒悟时刻:当要求我新增一个门电路类型时,我发现要在几十个if-else中寻找插入点,还要确保不影响到其他逻辑。那一刻,我理解了什么叫"代码耦合"。 - 设计模式的"真香"时刻
在第二次作业中,我尝试用继承结构来组织代码,但还是在Main.parseComponent()中埋下了复杂度18的"地雷"。 教训:
• 不要因为看起来"简单"就把所有逻辑堆在一起
• 工厂模式不只是书本上的概念,当你有10种组件要创建时,它会成为你的救星
• 一个方法超过20行,就该考虑拆分了
重构前后的对比:
// 重构前:一个方法做所有事
public static Component parseComponent(String line) {
// 解析类型
// 创建对象
// 配置参数
// 设置连接
// 返回对象
// 复杂度:18 😱
}
// 重构后:职责分离
class Parser { /* 只负责解析 / }
class Factory { / 只负责创建 / }
class Configurator { / 只负责配置 */ }
// 每个方法复杂度:<5 😊
3. 测试题的"细节魔鬼"
那些看似简单的判断题,让我明白了Java语言的精妙和"坑点": 浮点数除0的迷惑:
System.out.println(1.0 / 0); // 输出 Infinity
System.out.println(1 / 0); // 抛出 ArithmeticException
同样的除法,整型和浮点型处理完全不同!这个细节让我意识到:计算机是精确的,不理解"大概"。 接口的进化理解: 我曾经坚定地认为"接口只能有抽象方法",直到查阅资料才发现Java 8引入了默认方法。这教会我:技术是发展的,知识需要更新。
4. 注释的"打脸"经历
我总觉得自己代码写得很清楚,不需要注释。但一周后回看自己的代码:
// 这是什么意思?为什么是0x3F?
int mask = 0x3F;
// 这个循环条件为什么这么复杂?
for (int i = (n & 1) == 0 ? 0 : 1; i < arr.length; i += 2) {
// ...
}
心得:注释不是给现在的自己看的,是给未来的自己和接手的同学看的。9.8%的注释率,意味着90%的代码需要别人猜意图。
5. 继承体系的"甜蜜负担"
建立Component继承体系时,我享受到了多态带来的便利:
Component c = new AndGate();
Object result = c.computeOutput(inputs); // 统一的接口
但同时也遇到了问题:
• 基类设计不够完善,有些方法在子类中重复实现
• 新增功能时,需要在所有子类中修改
• 类型转换的混乱
反思:不要为了继承而继承。如果类之间没有真正的"is-a"关系,组合可能比继承更合适。
💡 收获的编程智慧
- 复杂度控制是硬功夫
• 一个方法超过10行,警惕
• 嵌套超过3层,重构
• 圈复杂度超过10,必须拆分 - 写代码要像写文章
• 有清晰的章节结构(类和方法)
• 段落分明(代码块)
• 注释如同批注,帮助理解
• 变量名是词汇,要准确达意 - 测试是最好的老师
• 边界条件总会找到你的漏洞
• 异常处理不是可有可无的装饰
• 别人的用例能发现你的盲区 - 设计需要远见
不要只考虑当前需求,思考:
• 如果要加新功能,改动有多大?
• 别人能看懂我的设计吗?
• 这个设计能应对变化吗?
🎯 未来编程的"避坑指南"
基于这些经验,我给自己制定了编程规范: - 单一职责原则:每个方法只做一件事,每个类只有一个变化原因
- 复杂度监控:写完后用工具分析圈复杂度,超过7就重构
- 注释三要素:为什么这么做、特殊逻辑说明、TODO标记
- 防御性编程:考虑所有异常情况,包括"不可能"发生的情况
- 持续学习:语言特性、设计模式、最佳实践要不断更新
🌟 最后的感悟
编程就像搭积木,初学者只追求"能立起来",有经验者考虑"结构稳固",高手思考"易于修改和扩展"。两次大作业和一次测试,让我从"能跑就行"走向了"优雅设计"。 最大的收获不是完成了作业,而是建立了对代码质量的敏感度。现在看到复杂的代码,我会本能地思考:"这里能拆分成多个方法吗?""这个设计符合开闭原则吗?" 踩过的坑,都是成长的台阶。感谢这些"痛苦"的重构经历,它们让我成为了更好的程序员。记住:好代码不是写出来的,是改出来的。
(4)总结:
这个数字电路仿真系统展示了良好的抽象能力和合理的继承设计,但同时也暴露出常见的初学者架构问题:
- "上帝类"反模式:Main类承担过多职责
- 硬编码依赖:组件创建逻辑固化
- 缺乏配置性:调整参数需要修改代码
- 注释不足:可读性和可维护性受影响
最大的收获:通过这个项目,我深刻理解了:
• 类图不仅是设计工具,更是思考工具
• 复杂度度量不仅是数字,更是质量信号
• 设计模式不仅是理论,更是实践指南
最终建议:采用渐进式重构,先解决Main类的职责过重问题,再逐步引入工厂模式、配置管理等高级特性。这样既能保证系统稳定性,又能持续提升架构质量。 这个项目不仅是数字电路仿真的实现,更是面向对象设计思想的实践演练。从"能运行"到"设计优雅",这是每个程序员成长的必经之路。


浙公网安备 33010602011771号