2025面向对象程序先导-OOpre心得

张振羽-24373282 2025-11-17 12:34:06

代码架构

最终架构设计

img

程序分为核心实体层、业务逻辑层、数据层、输入解析层和异常处理层。

业务逻辑层

包含 MainCommandHelper

程序将输入拆分为行后使用逐行传入 CommandHelper 对指令进行处理,CommandHelper 维护所有活动的 Adventurer 并包含所有具体业务逻辑的实现。在 Main 中对捕获的异常进行解析并打印。

核心实体层
1. Adventurer
  • 核心功能: 游戏的主角或实体。 维护角色的各项状态(hitPoint, baseAtk, baseDef, mana, money)以及各类物品(bottleList, equipmentList, spellList)。
  • 方法: 包含所有的游戏操作逻辑,如 fightusetakeItemchangeHitPoint help 等。
2. Bagpack
  • 核心功能: 管理冒险者当前实际携带的装备和药剂。满足限制: 只能携带一件武器 (carriedWeapon)、一件护甲 (carriedArmour),以及最多 10 瓶药剂 (carriedBottles)。
  • 方法: 在战斗或计算属性时,提供当前装备的攻防加成 (getWeaponAttack, getArmourDefense)。
数据层

该层定义了游戏中的所有可交互物品,采用经典的继承结构。

类名继承/实现核心属性核心功能
Item (abstract)Objectid所有物品的基类。
Equipment (abstract)Itemce (Combat Effectiveness)装备基类,拥有战斗效果值。
ArmourEquipment(extends)护甲类型装备。
Weapon (abstract)EquipmentWeaponType (Sword, Magicbook)武器类型装备。
BottleItemeffect, BottleType药剂类,具有即时效果(Hp, Atk, Def, Mana)。使用后标记为 used
SpellObjectmanaCost, power, SpellType (Heal, Attack)法术类,消耗 Mana,可用于治疗或攻击。注意:SpellItem 独立,但逻辑相似。
Factory
  • 实现了简单工厂模式 (Simple Factory Pattern)。
  • 提供静态方法 (createBottle, createEquipment, createItem),根据输入的类型字符串 (e.g., "HpBottle", "Sword") 实例化对应的具体物品对象。
  • 将物品创建逻辑与主业务逻辑(如 CommandHelper 中的物品添加)解耦。
输入解析层

包含 LexerParser

使用梯度下降对 lr 命令进行解析,完成批量导入

异常处理层

定义了一系列自定义运行时异常 (RuntimeException),用于在业务逻辑中精确地指示错误类型,并允许 Main 方法进行统一处理。

  • CantBeTarget :
    • FailureType: isDead, isBoss, notAlly
  • FailToUse :
    • FailureType: AlreadyUsed, LackOfMana, AtkLow
  • NoSuchItem:
    • 用于指示未找到指定的物品或冒险者 ID。
  • NotUsable:
    • 用于指示尝试对不适用的物品执行使用操作(例如对装备使用 use 命令)。

迭代开发

hw3

在此之前,所有核心业务在 Main 函数中实现,方法行数容易超过限制,不便进行 JUnit 测试。

将核心业务从 Main 中提取出为 CommandHelper ,方便进行测试,并能调用非静态方法。

在此次作业中首先出现了异常指令,考虑到后续异常指令可能的增多以及维护的便捷程度,定义一些运行时异常管理这些错误。

增加异常处理层,维护异常指令的输出。

hw5

Equipment 重写为抽象类,并在新类中维护具体方法

增加 Factory ,将物品实例化与 CommandHelper 解耦

后续架构未发生较大变动,仅对一些类添加方法

使用 JUnit 的心得体会

在使用 JUnit 中往往测试一个较大的类时会遇到需要重复实例化某种类,如

@Test
public void testConstructorAndGetId() {
    Armour armour = new Armour("armour1", 30);
    assertEquals("armour1", armour.getId());
}

@Test
public void testGetCe() {
    Armour armour = new Armour("armour1", 30);
    assertEquals(30, armour.getCe());
}

@Test
public void testGetType() {
    Armour armour = new Armour("armour1", 30);
    assertEquals("Armour", armour.getType());
}

这时我们可以使用 @Befor 来进行统一的初始化,如

@Befor
public void setup() {
    Armour armour = new Armour("armour1", 30);
}

单元测试可以进行模块化的测试,在测试时自底向上对正确性进行保证,这样可以大大减少测试的困难

好的测试用例有以下几个特点:

  • 已知输入和预期输出,即在测试执行前就已知。

  • 已知输入需要测试的先决条件,预期输出需要测试后置条件。

单元测试对测试用例有以下几个要求:

  • 每一项需求至少需要两个单元测试用例:一个正检验,一个负检验。
  • 如果一个需求有子需求,每一个子需求必须至少有正检验和负检验两个测试用例。

以及一些 Idea 使用技巧,你可以右键->生成->测试来一键生成对应的测试,接下来只需要在函数中填写代码即可。

img

学习OOPre的心得体会

面向对象的特性

封装(Encapsulation):把数据和操作这些数据的代码放到同一个对象里,并通过访问控制(如 private/public)隐藏内部实现,只暴露必要接口,从而保护对象的状态不被任意修改。
例:class BankAccount { private balance; public deposit(), withdraw() }

继承(Inheritance):子类从父类复用属性和行为,可以扩展或改写(override)父类的功能,体现“is-a”关系,便于代码重用和层次组织。
例:class Dog extends Animal { void bark() {} }

多态(Polymorphism):不同类型的对象通过统一的接口被同一段代码处理,调用在运行时绑定到具体实现(尤其是方法重写),提高灵活性和可扩展性。
例:Animal a = new Dog(); a.speak(); // 调用 Dog 的实现

抽象(Abstraction):从具体事物中抽出共性,定义抽象类或接口来描述“做什么”,而把“怎么做”留给具体子类,实现关注点分离和实现隐藏。
例:interface Shape { double area(); } // Circle/Rectangle 去实现

在面向对象的开发中,代码的耦合性降低,便于对对象进行维护,修改不会影响外部调用,扩展性强,新增功能只需添加方法。

面向对象和面向过程的区别

面向对象是注重对象的,在解决问题的时候会把事务抽象成对象的概念,并让每个对象维护自己的属性,执行自己的方法。

对OOPre课程的建议

增加课程强度,增加 hack互测, 增加课程作业次数,通常在一定量的作业后才会形成较为正式的代码架构,增加作业次数后可以使得代码调整的机会变多,并在形成正式架构后体会在面向对象编程中添加新业务的方便之处。

将最终心得体会拆分为每周博客作业,有助于博客内容的充实和社区交流。

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

271

社区成员

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

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