OOPre课程总结博客作业

沃行健-24371227 2025-11-04 18:34:58

作业架构设计及迭代调整说明

 

一、最终架构设计

迭代作业围绕 "冒险者 - 物品 - 关系" 的核心模型展开,最终架构采用面向对象设计,结合设计模式与数据结构实现复杂业务逻辑。主要包含以下模块:

  1. 核心实体类

    • Adventurer:冒险者类,维护属性(体力、攻击力、魔力等)、物品持有关系、雇佣关系及战斗 / 交互行为。
    • Item及其子类:Bottle(药水瓶)、Equipment(装备,含ArmourWeapon等细分类)、Spell(法术),封装物品属性与使用逻辑。
    • RelationManager:管理冒险者间的雇佣关系,维护上下级关系图。
  2. 工具类与管理器

    • Factory:采用工厂模式,负责创建各类物品(药水瓶、装备等)。
    • Observer相关接口:实现观察者模式,处理下级对上级的援助事件。
    • InputParser:解析输入指令,分发至对应处理逻辑。
  3. 核心逻辑模块

    • 战斗系统:实现物理 / 魔法攻击判定、伤害计算及结果处理。
    • 雇佣系统:维护有向森林结构,判定上级 / 盟友关系及行为约束。
    • 援助机制:监测冒险者血量变化,触发下级治疗流程。

二、迭代中的架构调整及考虑

1. 深浅克隆与调试

  • 核心需求:修复书籍与书架管理中的克隆问题,掌握深浅克隆差异。
  • 调整点:
    • BookBookshelf类实现深克隆方法,确保克隆对象独立(重写clone()或自定义复制构造函数)。
    • 修复容器克隆漏洞:对书架中的书籍列表进行遍历深克隆,避免引用共享。
  • 考虑:通过Object ID验证克隆独立性,解决因浅克隆导致的属性联动修改问题。

2. 容器与工厂模式

  • 核心需求:引入HashMap/HashSet管理物品,使用工厂模式创建对象。
  • 调整点:
    • HashMap存储冒险者及其物品(以 ID 为键),优化查找效率。
    • 新增Factory类,通过静态方法根据类型创建BottleEquipment等,减少代码冗余。
    • 细化装备类层次:Equipment → Armour/Weapon → Sword/Magicbook,通过继承实现属性与行为差异化。
  • 考虑:工厂模式降低对象创建与使用的耦合度,容器选择需权衡查询效率(HashMap)与去重需求(HashSet)。

3. 观察者模式与雇佣关系

  • 核心需求:实现冒险者雇佣关系及下级援助机制,应用观察者模式。
  • 调整点:
    • 引入Observable(被观察者)与Observer接口:上级冒险者为被观察者,下级为观察者,血量变化时触发援助。
    • 设计RelationManager维护雇佣关系图,通过 DFS/BFS 判定上下级及盟友关系。
    • 扩展fightuse指令逻辑,优先检查雇佣关系约束(如不可攻击上级)。
  • 考虑:观察者模式简化状态变更通知逻辑,雇佣关系图需高效维护(避免循环依赖,确保为有向森林)。

4. 递归下降法(词法 / 语法分析)

  • 核心需求:引入递归下降法处理复杂指令解析。
  • 调整点:
    • 新增Lexer类:拆分输入字符串为词法单元(如指令类型、参数),验证格式合法性。
    • 实现Parser类:基于文法规则(如<指令> → <类型> <参数列表>)递归解析词法单元,生成执行逻辑。
  • 考虑:递归下降法简化复杂语法解析,需定义清晰的文法规则以避免歧义。

三、架构设计原则与总结

  1. 封装与继承:实体类封装属性与行为,通过继承实现功能扩展(如Weapon继承Equipment)。
  2. 设计模式应用:
    • 工厂模式:统一物品创建入口,便于扩展新物品类型。
    • 观察者模式:解耦上下级关系,高效处理援助事件。
  3. 数据结构选择:
    • HashMap:用于 ID 与对象的映射,支持 O (1) 查找。
    • 邻接表:存储雇佣关系图,便于上下级关系遍历。
  4. 迭代优化方向:每次迭代聚焦核心需求(如克隆、设计模式、语法解析),逐步完善架构,确保模块低耦合、高内聚。

通过多轮迭代,架构从简单的类设计逐步演进为包含设计模式与复杂逻辑的系统,兼顾了可扩展性与业务复杂度。

使用Junit心得体会

 在面向对象编程(OOP)的学习与实践中,JUnit作为Java生态下主流的单元测试框架,不仅是验证代码正确性的工具,更重塑了我对“设计-编码-测试”全流程的认知。从最初为满足作业覆盖率要求编写测试用例,到主动通过测试驱动代码设计,JUnit让我深刻体会到单元测试与面向对象思想的深度契合,也暴露了实践中容易陷入的误区。以下结合多次OOP作业经历,分享我的核心心得。 

 一、JUnit:让面向对象的“封装”与“复用”更可验证 面向对象的核心特性之一是封装,即将属性与行为封装在类内部,仅暴露必要接口。但封装也带来了“黑盒风险”——若无法通过接口验证内部逻辑正确性,类的可靠性将大打折扣。JUnit恰好为封装的类提供了“接口校验器”,让我能精准验证类的行为是否符合设计预期。 在“冒险者-物品”系统的作业中,我曾为`Adventurer`类设计了`buyItem()`方法,用于处理购买装备的逻辑(扣除金币、添加装备至背包)。最初仅通过主程序打印日志验证功能,不仅效率低,还容易遗漏边界场景(如金币不足、装备重复购买)。使用JUnit后,我针对该方法设计了3组核心测试用例: 1. 正常购买:传入足够金币与新装备,验证背包中是否新增装备、金币是否正确扣除; 2. 金币不足:传入低于装备价格的金币,验证背包无变化、金币保持不变; 3. 重复购买:购买已有的装备,验证背包不重复添加、金币不扣除。 通过`@Test`注解标记用例,结合`Assert.assertEquals()`等断言方法,每次修改`buyItem()`逻辑后,只需执行测试类即可快速定位问题。例如,我曾误将“装备ID唯一性校验”写在`Adventurer`类的`addItem()`方法中,导致`buyItem()`未触发校验,而JUnit的重复购买用例立即报错,帮我避免了这一隐藏bug。 此外,JUnit的“复用性”也与面向对象的复用思想高度契合。在后续迭代中,当`Adventurer`类新增“出售物品”“使用药水”等方法时,我可复用之前测试类中创建的`Adventurer`实例、`Item`实例,只需新增对应方法的测试用例,大幅减少了重复代码,这与OOP中“类的复用”理念不谋而合。 

二、从“为测试而测试”到“测试驱动设计”:JUnit倒逼代码质量 最初接触JUnit时,我常陷入“为满足覆盖率要求而编写测试”的误区——机械地为每个方法编写用例,却忽略了测试与设计的关联。直到在“工厂模式创建物品”的作业中,我才意识到JUnit能反过来倒逼代码的面向对象设计更合理。 当时我需要实现`Factory`类,通过`createItem()`方法根据类型(如“HpBottle”“Sword”)创建不同物品。最初的代码直接在`createItem()`中用冗长的`if-else`判断类型,不仅扩展性差(新增物品需修改该方法),测试时也需为每个分支编写用例,代码臃肿且易出错。在编写JUnit测试用例时,我发现:若后续新增“ManaBottle”类型,不仅要修改`Factory`类,还需新增测试用例,违背了OOP的“开闭原则”(对扩展开放、对修改关闭)。 正是JUnit带来的“测试痛点”,让我重新优化设计:将`createItem()`拆分为`createBottle()`和`createEquipment()`两个方法,分别处理药水瓶和装备的创建,再在`createItem()`中调用对应方法。这样一来,新增物品类型只需扩展对应方法,无需修改原有逻辑;测试时也可针对`createBottle()`和`createEquipment()`分别编写用例,用例更聚焦,代码扩展性也显著提升。 这次经历让我明白:JUnit的价值不仅是“验证代码”,更是“提前暴露设计缺陷”。好的测试用例应与面向对象的设计原则(单一职责、开闭原则)相匹配,当测试用例编写困难、重复度高时,往往意味着代码设计存在问题——这正是“测试驱动设计(TDD)”的核心思想:先思考“如何测试”,再设计“如何实现”,让代码从源头就具备可测试性与可扩展性。 

三、JUnit实践中的常见误区与解决方案:在多次作业中,我也踩过不少JUnit使用的“坑”,这些误区本质上是对“面向对象测试边界”的理解不足,总结如下:

1. 过度测试私有方法,破坏封装性 面向对象强调“封装私有实现”,但最初我为了追求100%覆盖率,试图通过反射测试`Adventurer`类的私有方法。这种做法不仅繁琐,还违背了封装原则——私有方法是类的内部实现,若后续修改其逻辑,所有依赖该方法的测试用例都需修改,增加了维护成本。 解决方案:聚焦“公有接口测试”,通过调用公有方法(如`buyItem()`)间接验证私有方法的逻辑。例如,测试`checkBudget()`无需直接调用它,只需通过“金币不足时购买失败”的用例,即可验证其正确性。

2. 测试用例依赖外部环境,导致结果不稳定 在“书架管理”作业中,我曾在测试`Bookshelf`类的`loadBooks()`方法时,直接读取本地文件中的书籍数据。但不同环境下文件路径可能不同,导致测试用例有时通过、有时失败,失去了单元测试的“稳定性”。 **解决方案**:使用“模拟对象”或“内存数据”隔离外部依赖。例如,通过`@Before`注解在每次测试前创建内存中的书籍列表,而非依赖外部文件;若需测试数据库交互,可使用Mockito等框架模拟DAO层对象,确保测试用例不依赖真实环境。

3. 忽视异常场景测试,导致边界bug 面向对象的方法往往存在“正常路径”与“异常路径”,最初我只关注正常场景(如“成功购买装备”“成功添加书籍”),却忽略了异常场景(如“传入null值”“参数越界”)。例如,在测试`StringUtil`类的`substring()`方法时,未测试“起始索引大于结束索引”的场景,导致后续实际使用时出现空指针异常。解决方案:使用`@Test(expected = 异常类.class)`或JUnit 5的`assertThrows()`方法专门测试异常场景。例如,测试“传入null的装备ID”时,应验证`buyItem()`是否抛出`IllegalArgumentException`,确保代码对异常输入的处理符合预期。

四、JUnit是面向对象编程的“最佳搭档” 回顾多次OOP作业,JUnit不仅帮我发现了数十个隐藏bug,更重要的是,它让我对面向对象的理解从“语法层面”深入到“设计层面”: -它让“封装”更可靠,通过接口测试验证类的行为,避免封装带来的黑盒风险,让“复用”更高效,测试代码的复用性与业务代码的复用性相互促进,让“设计”更合理——通过测试痛点倒逼代码遵循OOP原则,提升可扩展性。 未来的编程实践中,我将继续以JUnit为工具,坚持“测试先行”的思想:在编写业务代码前,先思考测试场景;在优化代码设计时,同步优化测试用例。一段能通过所有测试用例的面向对象代码,不仅是“正确的”,更是“可靠的”“可维护的”。

 

从面向过程到面向函数转变的心得体会

从面向过程到面向对象编程的转变,对我而言不是语法的简单切换,而是一场从 “流程驱动” 到 “模型驱动” 的思维重构。最初以为只是多了 “类” 和 “对象” 的概念,直到在实践中反复碰壁又逐渐通透,才理解其中的本质差异。

面向过程时,思考起点总是 “这件事要分几步做”。比如写图书管理系统,第一反应是拆解流程:“输入信息→存数组→遍历查询→定位修改”。数据(图书信息)和操作(增删查改函数)是分离的,像把书和书架拆成了零散零件。

转向面向对象后,我学会了先抽象现实中的实体。图书管理系统里,“图书” 和 “书架” 是独立存在的实体:Book类封装 名称等属性和getInfo()方法,Bookshelf类封装容量属性和add()/remove()行为,最后通过bookshelf.add(book)实现交互。代码与现实世界的映射更紧密了,数据有了 “类” 这个容器,函数成了容器的行为,世界从扁平变得立体。

面向过程中,我曾因全局变量吃过大亏。为让方法访问数据,把数组设为全局变量。后来新增方法时不小心修改了数组,导致计算错误,排查时全局变量的 “牵一发而动全身” 让我耗费数小时。

用面向对象重构时,数据成了类的私有属性,仅通过get函数暴露读取接口,修改需经set函数)管控。外部函数只能通过接口访问,无法直接篡改底层数据。这种封装不仅提升安全性,更带来了 “边界感”—— 修改数据的存储方式(比如从数组换链表),只要接口不变,外部依赖就无需改动。

面向过程的 “复用” 常是复制粘贴。写了Dogbark(),再做Catmeow()就得复制修改;新增通用行为又得重写,维护时稍不注意就漏改。

继承让复用变得优雅:Animal基类封装eat()sleep()DogCat子类只需实现makeSound()。新增Bird时直接继承,无需重复基础行为。多态更让复用升维:用Animal数组存放各类动物,调用makeSound()时自动适配实际类型,新增Duck类只需实现接口,原有逻辑无需改动,完美契合 “开闭原则”。

从面向过程到面向对象,是从 “关注怎么做” 到 “关注是什么” 的视角跃迁。前者像写操作手册,后者像搭建微型世界 —— 先定义 “居民”(类),赋予属性和能力,再让他们按规则互动。这种转变,让编程从 “完成任务” 变成 “构建系统”,用更贴近人类认知的方式应对复杂问题,这或许是面向对象最珍贵的馈赠。

对OOPre课程的简单建议

可以对JAVA语法进一步细致讲解,可以适当放慢一点进度,使对内容学习更细致,许多内容靠自学有些难度

...全文
161 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

270

社区成员

发帖
与我相关
我的任务
社区描述
2026年北航面向对象设计与构造
java 高校
社区管理员
  • 孙琦航
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧