面型对象程序先导课程反思总结

焦子谦-22371047 学生 2023-11-05 01:53:37

一、程序架构设计

1.1.最终程序架构展示

img

其中,Belongings, Euqipment, Bottle 是抽象类,InputProcessor, Store, Arena均遵循单例模式设计。

我的设计中,值得注意的部分有:

  1. 主类(Main)功能

    最终版中主类的主方法仅负责获取InputProcessor的实例并调用启动方法,传入指定的数据来源(此处为System.in

  2. 输入处理器(InputProcessor)处理输入数据的方法

    最终版的输入处理使用了表驱动编程模式(可能并不标准,但是参考了吴际老师分享的资料),对输入处理方法进行了进一步封装,在输入处理器类中添加了一个方法容器:

    private final ArrayList<Consumer<ArrayList<String>>> funcList;
    

    此容器中的元素是参数为ArrayList<String>的方法(lambda表达式形式),使用了Java提供的Consumer接口。与之配套,输入处理器类中还有一个集中初始化各种输入处理方法的方法,在启动处理器时调用,示例代码:

    private void initFunctionList() {
        //0.占位
        funcList.add(null);
        //1.加入一个 ID 为 {advId}、名字为 {name} 的冒险者。
        funcList.add(in -> advs.put(in.get(1), new Adventurer(in.get(1), in.get(2))));
        //……
        //15.查询在 YYYY/MM 发生的有效战斗日志
        funcList.add(in -> arena.printTimeLog(in.get(1)));
        //……
        }
    

    容器中所有方法的参数都是本行输入经过处理后分离各个元素形成的ArrayList,方法体都只有一行,找到对应的冒险者或者竞技场的实例(后文会介绍竞技场的设计,项目中的冒险者容器和竞技场实例都由输入处理器管理),并传入相应数据,本来打算将输入的各个元素全都分开后传入String,但是后期部分指令元素过多,只能将整行传入。

    有了上述准备,输入处理器就只需要获取总行数,分别读入每一行,然后按格式进行划分,并根据第一个元素(指令编号)在方法容器中找到合适的方法即可。

  3. 竞技场(Arena)的设计

    这个类服从单例模式,其实例交由输入处理器管理,在涉及到相关指令时调用其中的方法。

    这个类的设计初衷是为了完成战斗模式的额外输入处理并生成、储存(按照日期)、输出战斗日志,并依次调用相应冒险者的有关方法实现战斗过程。

    这里可以看出,我的输入分散在两个类(输入处理器和竞技场)里,但是用的是一个Scanner(作为参数传入),我不清楚这算不算是一个好的设计,但是我认为这是在我的框架下相对简洁实用的一种方法了。

  4. 从属物品类(Belongings)及其部分子类的设计

    由于我认为装备,药水瓶,食物(以及它们的子类)更多地是拥有相同的属性和特征(id,name等)而非相同的行为(要说有也就是返回各个属性的方法),因此我选择建立了这个抽象类而没有用课程组建议的“价值体”接口。

    这个类的设计初衷是为了实现背包,有了这个类,背包就只需要一个容器就能实现了。

    值得一提的是,其子类Bottle、Equipment最终也被设置为了抽象类,因为最后它们都不在会被实例化。在实现这二者的子类的构造时,我用到了简单的工厂模式(实现这个功能时还没讲到设计模式,只是觉得这样做比较合适,可能不太标准),由抽象的父类用静态方法根据输入的需要实例化子类并返回。

以上四点是我自认为比较有趣的设计,其它类应该都是比较正常地完成功能,在此不再赘述。

1.2.迭代中的架构调整及考虑

        我个人感觉自己的架构相对稳定,虽然未必足够好,但是迭代过程中也没有遇到必须要大改甚至重构的问题,在此记录两点我印象比较深刻的架构调整

  1. 输入的处理方法

    最初我使用的是比较朴素的处理方法,在主类中处理输入,每行先读入对应的指令再根据指令格式一个个读入指令的元素,再找到对应的方法传入参数。

    后来随着指令增加,这种方法显得比较繁复,因此我使用了指导书中提供的输入处理方法,并进行了一些改动,具体来说,就是读一行处理一行,而不是全部读入再逐条处理,这样不必多开一个数组,也为我后来增加战斗日志的输入提供了一些便利。

    再后来,随着指令的增加,我的swich-case结构首先突破了行数限制,随后if-else结构也不堪行数之重负,故而最终我选择了独立出一个输入处理器类,并花很长时间研究了把方法存到容器里面的方法,最终形成了上个部分中描述的输入处理模式。

  2. ID等多类共有的属性的实现方法

    最开始的处理方法就是在各个类之间复制粘贴,更改其中的关键词。这里比较有趣的是我的id属性最开始用的是int型,后来发现它并不需要参与运算,只需要比较内容,因此为了方便传参(我的方法尽可能都用String参数,方便从输入处理处直接传入)而改成了String型。

    后来在实现背包的过程中考虑用同一个容器装三个类的对象,就研究了一下继承,尤其是向上类型转换的知识,把装备、食物、药水瓶的共同特征抽象成了从属物品类(我一度考虑过要不要连同冒险者类一起抽象为“游戏对象类”,但是当时感觉想实现的这个容器中没必要出现冒险者,后来也没有足够的需求让我实现这个类,就一直沿用现在的设计了),这样可以比较方便地实现背包,同时避免过多的复制粘贴带来的不可控效果。

    最后添加装备和药水瓶的具体种类式研究了一下抽象类,发现从属物品、装备、药水瓶都不会被实例化,就直接将它们写成了抽象类,供子类继承。

二、使用junit的心得体会

        我在本课程中第一次尝试自己系统性地构造数据对程序进行模块化测试,虽然写得仍然比较草率,但是这个过程中也的确学到了很多测试的思想方法,有了一些实践经验,也意识到一些问题,比如在对代码进行调整时原有的测试很可能也需要重写,另外就是如果自己对需求的理解有误,自己写的测试代码大概率还是测不出问题的,毕竟自己想得到的问题大多数都在写程序的时候解决了,我在全面思考方面的能力还需要增加,另外就是一个人去测另外的人的代码可能效果会更好一些,避免出现陷入思维死胡同的尴尬境地。

三、学习oopre的心得体会

  1. 关于版本管理

    在学习过程中逐渐意识到了版本管理的重要性,无论是可以及时调回前一个正确版本还是对比改动,都是很有用的功能,想来未来的多人协作开发更是如此。

  2. 关于自主测试

    我觉得这方面的收获甚至大于关于Java语言和面向对象编程知识的收获。感觉本门课相对于之前的变成课程一个很大的差别就是我们不能再一味依赖测评机,而是要自己写测试代码,甚至自己写测评机,这是一个很大、很重要的改变。虽然我现在模块化测试写得远不够好,测评机更是一点不会,但是至少知道了一个学习的方向,假期有时间计划多学一些测试方面的内容。

  3. 关于面向对象

    这学期同时选修了本门课和C++,结合此前的预习和课上课下的学习与实践,感觉对面向对象的编程思想有了进一步的把握,“封装、继承、多态”不再只是干巴巴的知识点,而成为了架构设计的一部分,相信我未来会对这种思想有更深刻的认识和体会。

四、对oopre课程的简单建议

最好别再用 “价值体” 这个接口,理由如下:

        个人认为课程组在让大家练习接口使用时在作业中的设计有点生硬了,“价值体”这个设计感觉是为了用接口而用接口,正如我上文解释架构时提到的,我认为这几个所谓价值体并不能算是有共同的行为。

        我大致观察了一下几份优秀代码,其中如果用到了这个接口,其中的方法也只是返回本身的价格,而这个方法我觉得更像是价格这个属性的附属方法,而不是一种独立的行为,因此我更倾向于用继承而不是实现接口来实现类似的效果。

        另外,我觉得作业虽然似乎比较倾向于让我们用一个容器装所有的被雇佣者、装备、药水瓶、食物(这个想法可能只是我个人的感受,因为我看优秀代码似乎也都没有实现这个容器),但是如果增加这个容器还需要在增删的时候都加一条代码,个人认为浪费空间同时比较容易出bug(比如哪个地方出现了增删但是忘了对这个容器进行操作),还不如在需要的时候依次遍历四个容器,这样工作量也没有很大,而且比较符合尽量不要改原有功能的原则。

        我认为如果需要使用接口,更好的例子应该是不同父类而有相同行为的类,比如在冒险者之外增加一个战斗机器人类,同样有攻击和受击行为,但是其属性可能会有较大的差别(这个例子可能也不够理想,但是大概是这个方向)。

以上只是一个初学者不成熟的小想法,可能有较大的谬误,敬请批评指正。

五、结语

本课程伊始确实让我有些措手不及,虽然预习过一些面向对象知识,但是git、checkstyle、junit(尤其是覆盖率检查)的学习都花费了我大量时间,但是习惯之后感觉写起代码来还是很舒服的,尤其是这种一点点实现大型项目的感觉对我来说极有成就感。

最后感谢老师和助教们的辛苦付出,可以感受到课上内容和作业指导书以及群里的适当提示都包含了许多心血十分感谢~~(*ゝω・)ノThanks!

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

301

社区成员

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

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