OOPre 课程作业总结:从架构迭代到 OOP 思维的蜕变
作为面向对象先导课程的结课作业,本次作业围绕 “冒险者系统” 展开,涵盖指令解析、雇佣关系管理、物品交互、战斗系统等核心功能。在迭代开发过程中,不仅完成了功能实现,更深化了对面向对象思想的理解。以下从架构设计、JUnit 测试心得、OOP 思维过渡体会及课程建议四个维度展开总结。
一、作业最终架构设计与迭代调整
本次作业的核心是构建一个可扩展、低耦合的冒险者管理系统,最终架构按 “职责划分” 分为核心实体层、工具支撑层、交互逻辑层三层,各模块职责单一且依赖清晰。
1. 最终架构设计(分层模块)
(1)核心实体层:封装业务核心对象
该层包含所有业务相关的实体类,通过类的继承与接口实现统一行为、区分差异,核心类关系如下:
- Adventurer(冒险者):系统核心对象,封装属性(血量、攻击力、金钱等)与行为(战斗、使用物品、雇佣关系管理),实现
AdventureObject接口; - 物品类:按功能分为
Bottle(药水)、Equipment(装备)、Spell(法术)三大抽象类,均实现Usable(可使用)或Carryable(可携带)接口,子类如HpBottle、Sword、AttackSpell各自实现具体的use()逻辑(多态应用); - 接口定义:
AdventureObject(统一对象 ID / 类型描述)、Usable(统一物品使用行为)、Carryable(统一物品携带属性),确保不同实体的行为一致性。
(2)工具支撑层:解耦通用功能
该层包含不依赖业务逻辑的通用工具类,降低核心模块的耦合度:
- Factory(工厂类):统一创建物品对象(如
createBottle()、createEquipment()),避免在Adventurer或Main中重复 new 对象,符合 “单一职责原则”; - Lexer(词法分析器):专门处理
lr指令的参数解析,将字符串拆分为标识符、括号、逗号等 Token,为递归下降解析提供支撑; - Main(入口类):负责指令读取与分发,调用各模块逻辑处理指令,不包含具体业务逻辑,仅承担 “调度者” 角色。
(3)交互逻辑层:处理指令与规则约束
该层通过Main的指令分发与Adventurer的方法实现,封装业务规则:
- 指令处理:
Main通过switch-case分发aa(创建冒险者)、ar(建立雇佣)、lr(批量导入雇佣关系)等指令,调用对应模块逻辑; - 约束检查:
Adventurer内置雇佣关系约束(isBoss()判断上级)、物品使用约束(checkUseConstraints())、战斗约束(checkFightConstraints()),确保业务规则不扩散到其他类。
2. 迭代中的架构调整与思考
本次作业并非一步到位,而是经历了 3 次关键架构调整,核心思考围绕 “降低耦合、提升可维护性” 展开:
(1)第一次调整:从 “硬编码创建” 到 “工厂模式”
- 初始问题:最初创建药水、装备时,直接在
Adventurer的addBottle()、addEquipment()中用new HpBottle()、new Sword()硬编码,若新增物品类型(如ManaBottle),需修改Adventurer类,违反 “开闭原则”; - 调整方案:引入
Factory类,统一负责物品创建,Adventurer只需调用Factory.createBottle(),无需关心具体实现; - 思考:工厂模式让 “对象创建” 与 “业务逻辑” 解耦,后续新增物品类型时,仅需修改
Factory,符合 OOP“对扩展开放、对修改关闭” 的原则。
(2)第二次调整:从 “扁平雇佣关系” 到 “树形结构 + 递归解析”
- 初始问题:最初仅支持
ar(添加单个雇佣)、rr(删除单个雇佣)指令,雇佣关系存储为 “直接上级 - 直接下级” 的扁平结构,无法处理lr指令的批量树形关系(如8kkY(vekV,x)); - 调整方案:
- 在
Adventurer中新增getAllSubordinates()方法,通过广度优先遍历获取所有间接下级,支撑树形关系管理; - 新增
Lexer类与parseAdventurer()递归解析方法,将lr指令的字符串参数解析为树形雇佣关系,动态调用addEmployee()建立关联;
- 在
- 思考:递归下降解析是处理 “嵌套结构”(如树形关系)的高效方式,通过 “分而治之” 将复杂解析拆分为 “解析单个冒险者”“解析冒险者序列” 等子问题,代码逻辑更清晰。
(3)第三次调整:从 “指令内联约束检查” 到 “统一约束方法”
- 初始问题:最初在
use、fight指令的处理逻辑中,直接内联雇佣关系检查(如if (target == adventurer.getEmployer())),导致相同的约束逻辑在多个地方重复,且难以维护; - 调整方案:在
Adventurer中封装checkUseConstraints()、checkFightConstraints()方法,集中处理约束检查,Main或useItem()仅需调用该方法即可; - 思考:“抽取共性逻辑” 是 OOP 的核心思想之一,通过统一方法封装约束规则,不仅减少重复代码,更让后续规则修改(如新增 “不能攻击盟友” 约束)只需改一处。
二、JUnit 测试心得体会
在作业开发中,通过 JUnit4 编写测试用例(覆盖Adventurer、Bottle、Factory等核心类),深刻体会到 “测试驱动开发” 对代码质量的保障作用,核心心得如下:
1. 测试的核心价值:提前暴露 “隐形 bug”
本次作业中,多个隐藏 bug 是通过 JUnit 测试发现的,最典型的是雇佣关系判断逻辑错误:
- 最初
isBoss()方法错误地判断 “目标是否将当前冒险者视为上级”(target.isBoss(this)),而非 “当前冒险者是否将目标视为上级”(this.isBoss(target)); - 编写
AdventurerTest.testIsBoss()时,构造 “a1→a2→a3” 的三级雇佣关系,测试 “a3 是否视 a1 为上级”,发现断言失败,才定位到逻辑颠倒的问题。
这让我意识到:手动测试难以覆盖所有分支(如间接上级、边界情况),而 JUnit 通过 “明确输入→预期输出” 的断言,能精准暴露逻辑漏洞,尤其适合复杂的业务规则(如雇佣关系、战斗伤害计算)。
2. 测试用例设计:“覆盖分支” 比 “覆盖行数” 更重要
最初编写测试时,仅关注 “行覆盖率”,但发现即使行覆盖率达到 80%,仍有大量分支未覆盖(如背包满时的物品挤出逻辑、死亡时的雇佣关系清理)。后续调整测试策略,重点关注 “分支覆盖”:
- 边界情况测试:如测试
takeBottle()时,构造 “背包已存 10 个药水” 的场景,验证 “新药水加入时,最早的药水被挤出”; - 异常场景测试:如测试
useItem()时,构造 “使用者死亡”“目标死亡”“物品不在背包” 等场景,验证指令是否按预期失败; - 递归逻辑测试:如测试
lr指令解析时,构造嵌套结构(如King(Knight(Archer),Rogue)),验证雇佣关系是否正确建立。
最终分支覆盖率从 27.4% 提升至 65%,代码的健壮性显著提升 —— 后续集成测试时,因分支未覆盖导致的 bug 减少了 70%。
3. 测试的 “副作用”:倒逼代码设计更合理
编写测试的过程,也是对代码设计的 “反向校验”。例如:
- 最初
Adventurer的cleanupEmploymentOnDeath()是私有方法,无法直接测试 “死亡时是否解除雇佣关系”; - 为了测试该逻辑,不得不重构代码:新增
getEmployer()、getEmployees()方法,暴露必要的属性(非直接暴露字段,而是通过方法封装); - 最终结果:代码的 “可测试性” 提升,同时也符合 “封装原则”(对外暴露方法而非字段)。
这让我明白:好的代码设计必然是 “可测试的”,而编写测试的过程会倒逼我们优化类的职责与接口设计。
三、学习 OOPre 的心得体会:从 “面向过程” 到 “面向对象” 的思维跃迁
作为从 “面向过程编程”(如 C 语言)过渡到 “面向对象编程”(Java)的核心课程,OOPre 不仅教会了语法,更重塑了我的编程思维,核心体会集中在三个方面:
1. 从 “关注步骤” 到 “关注对象”:拆分问题的视角转变
面向过程编程时,解决 “冒险者使用药水” 的问题,会按 “步骤” 思考:
- 检查冒险者是否存活;
- 检查药水是否在背包;
- 计算使用药水后的血量;
- 更新冒险者血量并删除药水。
而面向对象编程时,会按 “对象职责” 思考:
Adventurer(冒险者):负责管理自身状态(血量、背包),提供useItem()方法封装 “使用物品” 的逻辑;HpBottle(药水):负责实现 “使用时恢复血量” 的具体逻辑(use()方法);Main(入口):仅负责分发指令,不关心 “如何使用药水”。
这种转变的核心是 “职责封装”—— 每个对象只做自己擅长的事,代码结构更清晰,后续修改 “药水效果” 时,只需改HpBottle,无需改动Adventurer或Main。
2. 继承与多态:告别 “if-else 地狱”,实现代码复用
作业初期,处理 “不同物品的使用逻辑” 时,曾用面向过程的思维写过这样的代码:
java
// 反面例子:面向过程的if-else判断
if (itemType.equals("HpBottle")) {
target.setHitPoint(target.getHitPoint() + effect);
} else if (itemType.equals("AtkBottle")) {
target.setBaseAtk(target.getBaseAtk() + effect);
} else if (itemType.equals("AttackSpell")) {
target.setHitPoint(target.getHitPoint() - power);
}
这种代码的问题是:新增物品类型时,需不断加if-else,代码臃肿且易出错。
学习多态后,重构为:
- 定义
Usable接口,声明use(Adventurer user, Adventurer target)方法; - 每个物品类(
HpBottle、AttackSpell)实现use()方法,封装自身逻辑; Adventurer的useItem()只需调用usable.use(this, target),无需判断物品类型。
这让我体会到:多态是 OOP 的 “灵魂” 之一—— 它将 “做什么” 与 “怎么做” 分离,既实现了代码复用,又让扩展变得简单。
3. 设计原则:代码的 “长期主义”
课程中学习的 “单一职责原则”“开闭原则”“依赖倒置原则”,最初觉得是 “理论空话”,但在作业迭代中逐渐理解其价值:
- 若不遵循 “单一职责原则”,将
Lexer的解析逻辑写在Main中,后续修改lr指令格式时,需改动Main的大量代码; - 若不遵循 “开闭原则”,新增
DefBottle时,需修改Factory外的多个类;
这些原则的本质是 “为长期维护服务”—— 好的 OOP 代码不仅能完成当前功能,更能在需求变化时(如新增指令、新增物品),以最小的修改成本适配,这也是面向对象优于面向过程的核心优势。
四、对 OOPre 课程的建议
- 建议增加 “小型课程设计” 环节:当前作业以 “指令驱动” 为主,建议中期增加一次 “组队课程设计”(如开发一个简易 RPG 游戏),让学生在更贴近实际的场景中应用 OOP 思想(如角色、怪物、道具的交互),深化对 “类协作”“设计模式” 的理解;
- 建议补充 “调试与测试” 实践指导:课程中对 JUnit 的讲解偏基础,建议增加 “如何定位 OOP 代码中的 bug”“如何设计高覆盖度测试用例” 的案例教学(如结合作业中的 “雇佣关系逻辑错误”“递归解析异常” 等场景),帮助学生提升工程能力。
相关推荐
2023Fall-BUAA-OOPre-hw-8-summary
2023Fall-BUAA-OOPre-hw-8-summary
北京航空航天大学2024年秋季学期面向对象设计与构造先导课程实践项目_基于Java语言的冒险游戏设计与实现_面向对象编程思想实践与教学演示_包含类设计继承多态接口实现设计模式.zip
北京航空航天大学2024年秋季学期面向对象设计与构造先导课程实践项目_基于Java语言的冒险游戏设计与实现_面向对象编程思想实践与教学演示_包含类设计继承多态接口实现设计模式.zip
【工业自动化】欧姆龙PLC产品线与编程软件应用:从选型架构到调试排错的全流程技术指南
内容概要:本文《欧姆龙PLC与编程软件完全手册》系统介绍了欧姆龙PLC的产品架构、软件体系、通信协议、选型策略及编程调试技巧。重点区分了两大技术平台:基于CX-Programmer的传统C系列(CP/CJ/CS)与基于Sysmac Studio的新一代Sysmac平台(NJ/NX/NY),强调二者在软件生态、寻址方式和通信架构上的根本差异。手册详细对比了各系列PLC的性能参数,并提供与西门子产品的功能对标,帮助用户快速定位。深入讲解了编程操作中的关键问题,如任务结构设计、间接寻址、FB封装陷阱、在线调试五件套等,特别指出“FB使能关闭时状态不初始化”等易出错点。最后汇总了选型路径与现场避坑清单,极具实战指导价值。; 适合人群:具备一定工业自动化基础,从事PLC编程、设备调试、系统集成的研发工程师和技术人员,尤其是从西门子平台转向欧姆龙或参与新项目选型的1-5年经验从业者。; 使用场景及目标:① 新项目选型时判断应选用C系列还是Sysmac平台;② 编程调试过程中掌握高效操作技巧与常见问题排查方法;③ 实现跨平台迁移、系统升级或接手他人项目时规避架构与逻辑陷阱;④ 提升对欧姆龙PLC任务机制、间接寻址、FB设计等高级功能的理解与应用能力。; 阅读建议:本手册理论结合实践,建议按“先架构后操作”的顺序阅读,重点章节需结合实际工程反复演练。特别是FB设计规范、任务切换处理、强制操作收尾流程等内容,应在仿真环境中验证后再应用于现场。注意版本匹配问题,操作前确认所用软件与控制器固件版本兼容。
CISP-CSE注册云安全工程师备考资源包
CISP-CSE注册云安全工程师备考资源包
科技中介服务机构如何通过AI技术降低技术评估与匹配服务的操作门槛?.docx
科技中介服务机构如何通过AI技术降低技术评估与匹配服务的操作门槛?


