一、架构类图

- Main是程序入口,获取全部输入指令后交给Solution类处理
- 在Solution类中解析和执行指令
- 通过工厂模式,由BottleFactory类创建三类药水瓶的对象,EquipmentFactory类创建三类装备的对象,TreasureFactory类创建宝物对象
- BackPack类应用于Adventurer类内部,每个冒险者对象都有一个背包对象作为属性变量
- BattleManager是专门用于管理战斗的类,每次战斗处理前,需要先通过这个类设定攻击的发起者和承受者,指明攻击类型和使用装备,执行战斗时在本类中进行处理
- Welfare类用于处理福利兑换系统,可以调用冒险者消耗碎片的方法,并给予其福利
- Dungeon类用于处理副本闯关系统,内部只有一个方法:传入冒险者参数,依次挑战五只怪物,判断是否战胜并利用TreasureFactory生成宝物,应用宝物
- 我将BattleManager,Welfare和Dungeon都设为静态类,它们不产生实例对象,而是直接调用其静态方法来产生效果,不知道这样做合不合理qaq
- Bottle和Equipment都继承Item作为基类,指示可携带物品,Item类中包含的属性有id和name,方便统一管理
- 通过观察者模式,令Adventurer类现Defender和Empolyer接口,指明作为雇佣兵和雇佣者的行为
迭代过程及考虑
- 第二次迭代出现背包系统的时候,由于Adventurer类和BackPack类都要管理装备和药水瓶,我考虑应该讲这两类对象分别通过不同的容器来管理,还是把它们不分类型地装入Item类的容器统一管理。两种方法各有自己的优劣势:前者麻烦的地方在于每次增添物品,查找物品都要在两个容器分别进行,但在通过name查找时不会出现不同类型的物品重名的问题;而后者增添和按id(唯一标识)查找很方便,但涉及针对某种特定类型的物品进行处理时,难免总需要通过instanceof来确定类型。这两种策略到最后也没太弄明白哪种更好,但后期迭代时出现的新功能总是跟“携带”这一行为有关,于是最后采取了对于Adventurer中所有道具采取Item容器统一管理,BackPack中的携带道具采取了分两种特定容器管理的方法
- 作业初期输入的指令较少,且当时对面向对象思维尚不熟悉,指令的获取,解析和执行统一都放在了Main类里,但很快就发现这样做容易导致方法长度过长而扣代码风格分数,于是做了Solution类,将指令处理这一功能单独封装为一个类,Main类内容尽可能少
二、使用JUnit的心得体会
通过JUnit单元测试,由小到大,从最基本的功能测试,确认其无误后即可在一个中等层次进行数据构造测试,每一个test文件不需要针对过多的方法,而是针对某一特定功能尽可能全面地测试各种可能的情况。覆盖率的要求则是对代码测试的一个强制性的保证,每一次作业完备的测试要求也促进了本人在强测中没出现过一次bug。总体来说Junit测试是迭代开发中一个非常重要的环节,全面的测试也是代码质量的必要保障
但是,有一点直到最后我也很困惑,就是假如不想由于方法长度问题导致代码风格扣很多分,在Solution类的指令解析时就需要拆分出多个方法来对应处理不同的指令,而想要达到90%的覆盖率标准就必须对Solution类中的这些方法进行测试,然而不知道是不是因为这些方法直接或间接调用了本项目中绝大多数的其他方法,实际只测试这几个方法就能达到很高的覆盖率。可是只要我测试这些方法,提交后立即会报出存在非法行为的嫌疑,不测的话覆盖率又达不到。最后摆烂了,把分出来的那些方法全删了,全塞回到一个方法里解析
三、学习OOPre的心得体会
从面向过程编程过渡到面向对象编程是一个逐渐接受和理解的过程,开始时可能会疑惑,例如将对属性变量的访问强制性地改为调用get和set方法的意义究竟何在,又例如以前的c语言函数拥有所有数据的访问权限,我们能在一个函数中做很多事,但在面向对象编程中就需要考虑每一个对象所管理的数据和功能,通过各种对象之间的相互作用来实现需求。在学习的过程中就会慢慢发现,这种结构虽不像面向过程逐句执行那般清晰,但其实不同对象相互作用的关系非常符合我们人的思维方式,而面向对象的封装模式保证了高层次的调用对低层次的复杂处理过程的不可见性,这样会令代码更简洁,每一个方法的长度可以很短,同时减少在高层次调用中很多繁琐的、不必要的判断。
OOPre的课程学习体验非常符合我对面向对象编程的期望,新的代码思维感觉十分新颖和有趣,很喜欢这门课,期待下学期的正课
四、对OOPre课程的简单建议
- 有关git的自学希望提供更多的资料或视频讲解
- 可以提供一些Junit的使用技巧和示例