270
社区成员
发帖
与我相关
我的任务
分享
MainClass类:负责输入输出,维护所有的冒险者,指令的分配以及指令的顶层执行。

Adventurer类:负责维护单个冒险者的全部信息,以及冒险者与外界交互的全部基本行为。

Bottle类:负责维护药水瓶的基本信息以及展示嗑药效果的方法,下含四个子类HpBottle,AtkBottle,DefBottle,ManaBottle,继承override不同的嗑药效果。

Spell类:负责维护额法术的基本信息以及展示施法效果的方法,下含两个子类AttackSpell和HealSpell,继承override不同的施法效果。

Equipment类:负责维护装备的基本信息,同时用来维护武器和盔甲。

Lexer类和Parser类:梯度下降来实现lr指令导入冒险者雇佣关系树。
要求:实现冒险者,药水瓶,装备,创建冒险者和简单携带指令。
在MainClass中main完成输入和指令分配,借助ArrayList完成所有冒险者的维护,用static方法实现冒险者按名查询,创建实现几个指令的static方法。
创建Adventurer类维护冒险者基本信息,创建Bottle类维护药水瓶,创建Equipment类维护装备。
一开始把冒险者信息设成public,过不了CheckStyle,想一想确实应该封装一下满足封闭性,改成private加了public访问方法。
要求:药水瓶不同种类不同效果,增加法术,法术也是不同种类不同效果。可以携带Bottle和Equipment进背包,可以学Spell,可以使用Bottle和Spell。
为Bottle类添加子类维护不同类型的瓶子,通过继承override实现不同的效果,创建Spell类及其子类维护不同类型的法术。
MainClass中添加实现新指令的方法,分辨输入的Bottle和Spell类型的方法,Adventurer类中用ArrayList维护瓶子背包、装备背包以及能学法术的大脑,扩展冒险者的属性,添加指令中需要冒险者直接交互(学,装,带,用)的方法。
这次使用了子类继承并override了Bottle和Spell效果的方法,但是接口因为感觉多余并未使用。
要求:装备分成武器和盔甲,每种最多携带一个,武器有大宝剑和魔法书。对物品携带和使用进行了微调,加入了打人环节和金币系统。
这次讲了工厂模式,但是我在第二次迭代中已经在MainClass创建了分辨输入的Bottle和Spell类型的static方法,再整一个类属实没必要。因此,再添加一个分别Equipment类型的方法,把武器和盔甲背包简化成武器架和盔甲架,微调一下Equipment类中装备的效果,Adventurer类中修改Bottle的背包限制,调整添加移除装备的方法增加限制。
MainClass中加入打人指令和氪金买装备指令的方法,打人用ArrayList存挨打名单,按照题面要求模拟打人和氪金流程。打死了之后会爆金币,因此要在Adventurer类中添加自己爆金币的方法,负责将爆的装备转换金币,和自带的金币一块供上来。
值得注意的是,1v10的时候每个人的防御都是整体的防御,Command时漏处理会挂强测。
这次迭代有的同学把Bottle,Spell,Equipment统一化管理,我认为就三种还不至于管不过来,之间的差异性也容易导致使用时出bug,因此作罢。
要求:加入雇佣关系和援助行为
MainClass添加雇佣方法和取消雇佣方法。main中加的输入和指令分配太多CheckStyle超60行,把输入和指令分配精简压行,拆分到solve方法中。
Adventurer类中添加Master变量和Slave的ArrayList,这样用(伪)递归就可以实现判断直接&间接Master的方法。
MainClass的use方法中,提前加入判断Boss和Ally的方法;fight方法中,提前加入判断Boss,添加是否援助的判断(用HashMap保存挨打前的Hp);添加seekHelp方法求援。
Adventurer类中添加help方法(自己帮Boss)。
为啥我要整一个seekHelp:观察者模式有点多此一举,实际上只需要把MainClass中维护的冒险者ArrayList拿出来,每一个看一下能不能帮上忙(判断自己是不是Boss)。这就是求援的简单实现。
要求:添加lr指令导入冒险者雇佣关系树
用题面给的Lexer类处理输入的字符串,自己加一个Parser类模拟一下梯度下降,MainClass加一个lrCommand方法,速通了。
在Junit测试中,自己构造小数据模拟各种情况,使用assert比对可以很快的发现bug。在C语言调试中,我一贯是在各种位置手动输出(人肉设置断点)的,多少有点繁复,整上Junit立刻感觉简单了不少。
为什么Junit测试更加方便?我认为源自Java这种面向对象编程语言模块化的特性,可以分别测试类以及内部的方法。此外,Junit以覆盖率运行,可以更好地发现有没有覆盖全部的行数和分支。
比较遗憾的是,评测时不能使用反射,导致MainClass中包含Scanner输入的方法无法测试,对达成覆盖率要求有一定影响。因此,最好将输入集成到一个方法中(不一定非要用提示给的方法,可以边读边处理),这也比较符合程序的IO思想。
学习OOpre主要是以学习Java语言为基础体会面向对象编程的特性。和之前学习的C语言不同,Java不再是基于函数过程编程,而是通过类对象的构建,以及不同类之间的交互实现编程。
面向对象编程的优点是以类为基础,一旦架构确定,迭代时不会有大的结构化调整。修改时只需要把任务分成:类里面加东西and类之间加交互,不容易被逻辑绕晕。
但是面向对象编程缺点也很明显。任何问题实际上都是面向过程的,把问题拆分成对象以及对象间交互,构建类的过程无疑是复杂且存在冗余或冲突的。虽然封装、继承、多态能一定程度降低冲突和复杂度,但是依然难以避免。身边的同学创造的各种类、接口编织成一张混乱的网,却常常发现有些东西从来就没用过or几乎只用过一两次,食之无味,弃之可惜啊。
在思路从面向过程到面向对象的转变中,我不可避免地保留了面向过程的思路,这体现在我的架构和完全面向对象的架构有较大区别,主要代码集成在两个类:MainClass(负责IO和Command)和Adventurer(负责一切与冒险者直接相关),其他类虽然也使用了封装继承等用法,主要只负责维护自身功能“辅助”冒险者。有的同学把Command未经拆分直接当成了冒险者的交互方法,使用了复杂的关系实现,也添加了很多辅助的类。我认为过度强调面向对象,把一切过程都对象化,很容易创造出史山。因此,我的设计虽然有点强调中央集权,在宏观架构方面保证了“小而美”的简洁性。
在后续OO正课的学习中,我认为面向对象的思想和语法要多学多用,但在过程实现好于对象实现时,不应该舍近求远。
希望加强课上和课下的联系,现在课下只看网站教程就把作业写了,有点CO理论和实验的割裂感。