面向对象课程先导课总结
22373321-张瀚文
整个课程总共七次迭代,并借助迭代学习了不同的Java知识点和面向对象编程的思想。整个过程中既有一遍ac的快乐,也有debug到深夜的心碎。总的来说,无论是对Java语言基础知识的学习,还是程序架构以及编程能力的提升,先导课都对我产生了非常深远的影响。
程序最终架构
使用表格来展现最终的程序架构
名称 | 类型 | 说明 |
---|---|---|
Main | 类 | 包含程序的入口,同时兼有解析输入信息,进行战斗日志有关的操作。 |
Adventurer | 类 | 类中使用不同的HashMap储存冒险者所拥有的物品,使用不同的方法实现跟冒险者有关的各种操作 |
Bottle | 类 | Bottle类型的父类,包含Bottle类的基本属性,如capacity,price等;包含get类方法(如getId,getPrice,getCapacity等),set类方法(setEmpty等) |
RegularBottle | 类 | Bottle类型的一个子类 |
RecoverBottle | 类 | Bottle类型的一个子类,有自己独特的属性 |
ReinforcedBottle | 类 | Bottle类型的一个子类,有自己独特的属性 |
Equipment | 类 | Equipment类型的父类,包括Equipment类的基本属性,如star,price等;包含get类方法(如getId,getPrice,getStar等),set类方法(addStar等) |
RegularEquipment | 类 | Equipment类型的一个子类 |
CritEquipment | 类 | Equipment类型的一个子类,有自己独特的属性 |
EpicEquipment | 类 | Equipment类型的一个子类,有自己独特的属性 |
Food | 类 | Food类,包含Food类的属性,如price,energy等;包含get类方法(如getId,getEnergy等) |
Factory | 类 | 工厂,负责在冒险者买东西时根据类别新建对象。 |
Shop | 类 | 单例模式,直接在类中实例化对象,并提供访问方法;设置三个HashMap用于储存adventurer卖的各类东西;设置计算物品价格的方法以便Factory新建物品时使用。 |
Commodity | 接口 | 定义共同方法getPrice,Bottle类,Adventurer类,Food类,Equipment类均需实现此方法。 |
迭代中历次出现的bug总结和结构考虑
-
第三次作业:
- 结构:新增背包功能,在
Advneturer
类中添加三个HashMap
表示背包. - bug:检查药水是否被携带时,错误的在
bottles
(拥有的瓶子),而不是在carrybottles
(携带的瓶子)中遍历
- 结构:新增背包功能,在
-
第四次作业:
- 结构:新增冒险日志功能,没有新增类,而是直接在main类中新建方法进行匹配,查找和信息打印(导致了main类代码行数过大)
- bug:注意
scanner
只有一个;数组的下标写错;打印信息时少打印了空行
-
第五次作业:
-
结构:本次作业没有迭代,而是基于常见的错误对已给代码进行debug
-
bug:搞混了空串和
null
的概念,空串调用方法不会出错,但是null调用方法会抛出空指针异常。incantation = ""; //not incantation = null;
-
-
第六次作业:
-
结构:新增继承和接口,添加若干子类。使用
commodity
接口统一管理Adventurer
、Bottle
、Equipment
、Food
-
bug:中测和强测各出现了一次bug
-
新建物品时id错误的使用了冒险者的id而不是物品的id
-
强测时发现自己第四次作业对于冒险日志的处理还是不够成熟,本来是使用
log
数组和advInFight
数组同步进行战斗日志的记载,以期达到后续便于查找攻击者和被攻击者的目的。/*array saved the type,date,adver */ int index = logAdventure.indexOf(array); ArrayList<String> arr = advInFight.get(index);
然而这种通过这种方式找到的索引忽略了一种情况,即对于多个相同数据,
indexOf
方法只返回索引的最小值。
-
-
-
第七次作业:
- 结构:新增
Shop
类、Factory
类。其中shop
类采用单例模式,Factory
类作为工厂生产冒险者需要买的物品 - bug:在
Factory
类新建物品时,本来应该是RegularBottle
类,但是新建成了Bottle
类,导致在查询类时找不到RegularBottle
类。
- 结构:新增
总结以上bug类型,其实很多bug都可以通过在第一遍写的时候小心谨慎一些来避免。同时回顾我的debug过程,个人认为就debug的速度来说:硬看 > 调试。但是就debug的定位而言,调试 > 硬看。因为第六次作业强测debug时,我硬看看了一个小时也没看出来,但是后来把强测数据点一千五百多行硬调试了一遍,花了一个半小时多,最后找到了问题。
从优秀代码中获取的经验和自我反思
- 可以设置单独的
bag
类作为冒险者的背包,并在其中进行背包有关的操作,而不是直接在冒险者中通过设置很多的HashMap
来表示背包,代码过于臃肿(冒险者类多达400余行) - 针对我的代码中main函数过于冗长的改进方式:
- 设置单独的
IO
类,Main类中只新建IO类的实例io,并读取操作数n,之后均通过io对输入进行解析。 - 去除Main类中过于具体的操作,下发到类中调用方法实现,比如新建一个冒险者,药水瓶等等,不能全在Main类里new一个对象。
- 需要优化冒险日志的处理,我的Main类过长的原因之一:把所有对战斗日志的处理,包括匹配打印等等全部写在了Main类里面,属于是迭代时没有好好思考代码架构。
- 设置单独的
- 究竟如何处理冒险日志:
- 纵观优秀代码,对于冒险日志基本上都是设置了一个专门的类,在类中进行相应的匹配,打印,或者查找。
- 而日志储存时可以通过多储存一个类别信息而降低后续的查找和判断难度。
程序架构上的自我反思:
- 新增功能时,优先考虑增加类,而不是增加函数来实现(体现在冒险日志上)
- 之后再遇到多类型输入的时候要注意新增类处理,而不是全放在Main类里处理。
- Main类中无论如何都不放具体的执行和实现方法,只是一个程序的入口。保证Main类的纯粹性。
Junit
在第六次作业之前,我都一直没有怎么重视junit
的作用,直到第六次作业,我发现Bottle的id跟实际添加的id不相等,junit的报错让我找到了bug的时候,我才真正意识到Junit的重要性。
- 为确保方法覆盖率,应当尽量对每一个能够测试的方法都进行测试对拍
- 为确保每一个分支都尽可能地被覆盖到,要构造不同种类的数据
- 为了便于测试,在对应的类中可能需要添加一些set和get的方法以获得数据
学习oopre的心得体会
- 通过oopre掌握了Java语言的基础编写能力,以及很好的提升了我的代码风格!!!
现在回头看自己大一写的C语言的风格完全看不下去。 - 从面向过程到面向对象的过渡无疑是艰难的,但通过一次次的迭代,对代码结构的调整,我深刻体会到了面向对象编程的魅力。
- 对于代码架构的分析和优化任重而道远。如何处理多种输入?如何处理新增的功能?倒数第二节课介绍的各种模式,以及本次作业分享的优秀代码的架构都让我叹为观止,回头再看自己的代码简直不忍直视。要在随后的学习中通过不断地应用和重构逐步体会。
- oopre很好的锻炼了我的心态和身体素质。包括但不限于调试一千多行代码锻炼了我的手部力量;周三好不容易de完中测bug但是周五又发现自己强测有bug同时新的任务也布置下来的无力感……但是!跟终于找到了bug并解决的快感相比起来,这些折磨都不算什么。
- 只要代码写的够对,所有测试都不在话下,只要能被测出来问题,就说明有地方考虑不周,就是需要改进。
- 非常感谢帮助解决问题的老师、助教和同学,你们辛苦了(鞠躬)
对oopre课程的建议
希望作业可以早一点布置。 不然和co撞在一起太难顶了/(ㄒoㄒ)/~~
对工具链的下载安装那个教程可以再优化一下~