OOPre 课程总结

邓宇翔-24373294 2025-11-17 23:40:04

作业架构设计

  • 初始架构(第二次作业)

初始架构比较简单,我按照课题组的要求实现了冒险者类 Adventurer、药水瓶类 Bottle 和装备类 Equipment

MainClass 类中,我用 ArrayList 容器来管理所有冒险者,同时在 Adventurer 类中,我也用 ArrayList 容器管理每一个冒险者所拥有的药水瓶和装备。

对于每一条指令,我都封装了一个方法实现对应的功能,并在 MainClass 类中用 if - else 语句跳转到对应的方法。

  • 第一次迭代(第三次作业)

此次迭代加入了接口和继承的概念。

对于四种不同的药水瓶,我分别实现了四个类,并令他它们继承 Bottle 类作为其子类。

对于两种不同的法术,我直接实现了 Spell 类,将两种法术放在一起处理。

以上二者均需实现 use 方法,因此我实现了一个 Usable 接口,并令二者作为该接口的实现。

对于冒险者各种属性的修改,我在 Adventurer 类中实现了若干方法修改。

对于冒险者的背包限制,我用另外一个 ArrayList 容器管理冒险者携带的药水瓶,而由于目前而言装备携带与否并不重要,因此我没有实现相关功能。

对于冒险者死亡导致指令执行失败的情况,我在 MainClass 类中各指令对应的方法里进行判断。

最后,我将 MainClass 类中 if - else 语句跳转各指令对应方法的部分改为了 switch - case 语句实现。

  • 第二次迭代(第五次作业)

对于 Equipment 类的细化,我分别实现了 Armour 类和 Weapon 类,令它们继承 Equipment 类作为其子类,同时实现 Sword 类和 Magicbook 类,令它们继承 Weapon 类作为其子类。

对于冒险者的背包限制,我对 “可携带” 这一概念实现了一个父类 Item,并令 Bottle 类和 Equipment 类作为其子类,该类设计了和携带相关的若干变量和方法,而携带这一行为我还是在 Adventurer 类中实现了相关方法。

对于战斗功能,我在 Weapon 类中实现了 fight 函数,并对两个子类按照要求复写。

对于金钱系统,我在 Adventurer 类中设计了若干变量和方法,同时在 fight 函数中也实现了相关方法。

此次迭代还进行了一些别的修改:

  1. 将两个法术分为两个类并继承 Spell 类作为其子类;

  2. 实现 CommandFactoryCreationFactory 类,采用工厂模式,前者实现命令的分发,后者实现对象的创建;

  3. 除管理已携带药水瓶的容器仍为 ArrayList 类型外,其它容器均改为 HashMap

  • 第三次迭代(第六次作业)

此次迭代加入了雇佣关系。

对于每个冒险者,我分别维护其直接上级(即雇佣其的冒险者)和其直接下级(同理,采用 HashMap 实现),在相关指令生效时,对涉及到的冒险者进行修改,同时冒险者死亡时,需删除所有相关的关系。

对于雇佣关系的约束,我先在 Adventurer 类中实现了 haveBossisAlly 方法用于判断上下级关系,然后在 use 函数和 fight 函数执行前先通过这些方法判断是否可执行。

对于冒险者援助,我的实现比较潦草,这也导致我挂掉了强测中的一个测试点。无论如何,我先在 Adventurer 类中实现了一个 aid 方法。最初,我是在修改冒险者体力值的方法中判断是否需要援助,但是由于援助信息是在指令结束后才输出,因此这并不可行。后来我的实现是将 fight 函数改为先输出指令结束后各目标冒险者剩余体力值,然后再实质性在对应的对象中修改。实际上也可以用一个容器将需要援助的目标冒险者暂存,指令结束后再遍历容器并对它们进行援助。

  • 第四次迭代(第七次作业)

此次迭代加入了利用递归下降,实现批量导入指令的功能。

我先将示例的 Lexer 类完成填空,加入到项目中,然后在相关指令的方法中实例化该类,再实现了一个递归函数用于处理该指令。


我的总架构设计综上,项目结构如下:

  • MainClass

  • CommandFactory

  • Adventurer

  • Item

    • Bottle - Usable

      • HpBottle

      • AtkBottle

      • `DefBottle

      • ManaBottle

    • Equipment

      • Armour

      • Weapon

        • Sword

        • Magicbook

  • Spell - Usable

    • HealSpell

    • AttackSpell

  • Usable ( Interface )

  • CreationFactory

  • Lexer


JUnit 使用心得

与其说是 JUnit 的使用心得,不如说是测试代码的心得。OOPre 的作业体量很大,之前习惯性采用的静态差错法和输出调试法都不太管用了,比较适用的则是对代码里的每个类、每个方法、每一条分支、每一行代码都进行全面的测试。

JUnit 的方便之处就在这里,它除了包含若干断言语句,可以帮助我们判断程序运行是否符合期望之外,还有覆盖率的显示,能够精准刻画哪些地方是进行了测试的、哪些地方是未被覆盖的等等,这可以帮助我进行更好更全面的测试。

在进行了若干次作业的 JUnit 测试撰写后,我深刻意识到工程代码进行全面测试的重要性。不仅是 OO,CO 等科目也是一样。这段独特的经历会督促我之后养成良好的习惯,不对自己的代码盲目相信,而是尝试用结果说明一切。


OOPre 学习心得

以前我在编写程序设计竞赛中体量较为庞大的代码时,觉得只要封装足够,实现起来就会非常轻松,当时的我并不明白为什么 OO 这一件事情为什么能这么吸引人研究,甚至能够成为一门课程。

现在看来面向对象编程真的是一门很深奥的学问。其实我以前觉得的也没错,如果能对需要实现的功能进行十分合理的封装,那么实现起来将会非常简洁优美,但实际上这并不是一件多么简单的事情,各个类型之间有相似也有区别,要怎么合理的通过各种设计进行封装,哪些可以一起实现,哪些需要分开,哪些需要继承,哪些需要接口,这些都不是简单的 “打包” 就能够实现的。

除此之外,OO 还需要注重代码的可迭代性 —— 工程如果是一坨 “石山”,维护起来特别麻烦,那如果需要新功能就会很繁琐。在设计的时候,除了需要考虑功能封装,还需要注重这种可迭代性,例如我如果出现了一个新的类,我肯定不能从头开始写这个类的所有属性,这样就特别麻烦,如果设计合理,我将这个新类继承一下,或是作为某个接口的实现,这样我只用注重这个新类与别的类不同的地方就可以了,非常方便;如果许多相似的类都需要新增一个功能,那我对每个类一个个添加这个功能,和西西弗斯没有区别,那如果我设计时就考虑到这些类本身就非常相似,因此将他们都继承到一个父类上去或是作为一个接口的实现,那么我在这个顶层的类或接口上实现这个功能,就可以一口气全部添加上了。

OOPre 作业的迭代过程也算是比较跌宕起伏了,修改到后面愈发觉得自己的代码像石山。非常期待进入下学期的 OO 正课,锻炼自己的设计思维!

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

270

社区成员

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

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