271
社区成员
发帖
与我相关
我的任务
分享本次作业的核心目标是构建一个基于文本指令的冒险者模拟系统。在最终的架构中,我主要围绕以下几个核心模块进行设计:
实体与模型层(Model): 这是整个系统的基石。Adv (Adventurer) 类是当之无愧的核心,它封装了冒险者的所有属性(HP, ATK, MNY等)和行为(战斗、使用物品、建立关系等)。Item 和 Spell 作为抽象基类,通过继承派生出 Equipment、Bottle、AttackSpell 等具体子类,形成了一个清晰的物品和技能层次结构。这种设计充分利用了继承和多态,使得添加新类型的物品或技能变得非常方便。
业务逻辑层(Logic/Controller): Main 类承担了主控制器的角色,它负责接收用户输入,并调用相应的方法来驱动整个程序的逻辑流。新增的lr指令,我将其解析逻辑独立出来,封装到了新的Parser和Lexer类中。Parser通过递归下降的方式解析复杂的雇佣关系字符串,而Lexer则负责将字符串分解为一个个有意义的词法单元。这种职责分离的设计使得Main类的逻辑更加清晰,也让复杂的解析任务变得易于管理和测试。
工厂模式的应用: Factory 类是本次架构中的一个亮点。它将对象的创建过程集中管理,使得Main类在需要创建物品或法术时,无需关心具体的子类构造细节,只需提供类型字符串即可。这有效地降低了模块间的耦合度,提升了代码的可维护性和扩展性。
在迭代过程中,最大的调整是从一个扁平化的指令处理逻辑,演变为引入专门的Parser来处理复杂语法。最初,所有指令都在Main类中通过简单的if-else或switch处理。但lr指令的复杂性让我意识到,将语法解析的职责分离出来是至关重要的,这使得代码结构更加清晰,也更符合单一职责原则。
在本次作业中,我投入了相当一部分精力来编写JUnit单元测试。起初,我认为写测试代码是一项额外的负担,但很快便体会到了它的巨大价值。
首先,JUnit是代码正确性的守护神。通过为每个类和关键方法编写测试用例,我能够精确地验证每一部分代码的功能是否符合预期。当我添加新功能或重构旧代码时,只需重新运行一遍测试,就能立刻发现是否引入了新的Bug。这给了我极大的信心去优化和调整代码结构。
其次,测试驱动开发(TDD)的思想深刻地影响了我的编程习惯。在实现Parser类时,我尝试先编写测试用例,明确定义输入和预期的输出,然后再去实现具体的解析逻辑。这种“先写测试,再写代码”的模式,迫使我在动手编码前就深入思考功能的边界条件和各种可能性,使得最终实现的代码逻辑更严谨、鲁棒性更强。
最后,JUnit测试是代码最好的文档之一。当我回顾AdvTest.java时,通过测试方法名和断言(Assertions),我能迅速地理解Adv类的各种功能点和使用方式,这比阅读大段的注释或源代码要高效得多。
学习面向对象编程,对我而言,最深刻的体会是一次思维模式的根本转变。
在接触OOP之前,我的编程思维更偏向于“面向过程”。我会首先思考“程序应该做什么?”,然后将任务分解成一步步的函数调用。这种方式在处理简单问题时很有效,但当系统变得复杂时,函数间的调用关系会变得错综复杂,数据和操作它们的过程是分离的,维护起来非常困难。
而OOP教会我首先思考“系统中存在哪些实体(对象)?”。对于作业,我不再是想“如何实现战斗?”,而是想“‘冒险者’这个对象,应该具备一个fight的行为”。数据(如HP, ATK)和操作这些数据的行为(如setHp, fight)被封装在对象内部,对象成为一个独立单元。这种从“动词”(过程)到“名词”(对象)的思维转变,是我最大的收获。
通过封装、继承和多态,我能够构建出一个更贴近现实世界问题的模型。例如,Bottle和Spell都实现了Usable接口,使得use指令可以统一处理这两种截然不同的事物,它让我的代码变得更加灵活和易于扩展。
建议在作业说明的专业术语之外,补充一些帮助零基础同学理解的生动描述()