任务简介
本次课程的任务是写一个简单的小游戏,目的在于让学生们提前接触面向对象编程思想。
一、架构设计
本人对于每一个类的架构设计如下:
Adventure
的对象储存于Main函数中的ArrayList<Adventure
>
Bottle
类并不是使用继承实现的,理由是为了一两个方法和一个属性专门写一个继承实在是不值得。用一个double
类型的others就能储存属性,再用一个方法getEffect()
对不同type
的Bottle
来获取他们的使用效果就足以满足所有要求了,而且代码集中化的好处在于阅读起来不用切屏。
Equipment
类同Bottle
Food
类同Bottle
Bag
背包内含3个Section表示不同的背包区域。
BattleLog
表示战斗日志,用字符串存储,并内置输出、获取日期、获取攻击者等方法
Adventure
- m o n e y money money, h i t p o i n t hitpoint hitpoint, i d id id, n a m e name name, p r i c e price price, l e v e l level level, c o m m o d i t y N u m commodityNum commodityNum
- HashMap<
Bottle
> b o t t l e bottle bottle - 拥有的药水 - HashMap<
Equipment
> e q u i p m e n t equipment equipment - 拥有的武器 - HashMap<
Food
> f o o d food food - 拥有的食物 Bag
b a g bag bag - 携带- ArrayList<
Adventure
> h i r e d hired hired- 雇佣 - ArrayList<
BattleLog
> a t k L o g atkLog atkLog - 攻击日志 - ArrayList<
BattleLog
> a t k e d L o g atkedLog atkedLog - 被攻击日志
Bottle
- i s E m p t y isEmpty isEmpty, p r i c e price price, c a p a c i t y capacity capacity, i d id id, n a m e name name, t y p e type type, o t h e r s others others
Equipment
- p r i c e price price, s t a r star star, i d id id, n a m e name name, t y p e type type, o t h e r s others others
Food
- p r i c e price price, i d id id, e n e r g y energy energy, n a m e name name
Bag
- HashMap<
String
, ArrayList<Bottle
>> b o t S e c botSec botSec; - 携带的药水 - HashMap<
String
,Equipment
> e q u S e c equSec equSec; - 携带的武器 - HashMap<
String
, ArrayList<Food
>> f o o d S e c foodSec foodSec; - 携带的食物
- HashMap<
BattleLog
int
t y p e type type;1->use bottle | 2->pvp | 3->aoe
String
c o n t e n t content content;
Shop
-
s
t
a
t
i
c
static
static
Shop
s h o p shop shop - 商店(单例模式) - HashMap<
String
, ArrayList<Record
>> r e c o r d record record - 商店记录
-
s
t
a
t
i
c
static
static
Record
String
t y p e type type - 详细种类long
p r i c e price price - 价格int
a t t r attr attr - 参数(武器为star,药水为capacity,食物为energy)
Io
- 输入输出类- 属性不重要,里面全是方法
- $Op$1-23
Main
Io
i o io io - 包含唯一的一个输入输出类- ArrayList<
Adventure
> w o r l d world world - 储存所有的冒险者
Commodity
- 价值体接口,内置一个getPrice()方法
二、Junit体会
三句话:多做测试!多做测试!多做测试!
-
前期因为assert语句给我带来了极大的苦恼,于是后来就没有写assert语句了。事实证明这个选择也不差:手动判断比自动判断花的时间少不少,不用为每一行的输出都做判断。
-
尽量对每一种情况都做测试,这样更容易找出bug。
-
Junit的测试是认为写的,因此当人自己犯错的时候,Junit是无辜的👀举个例子,如果理解题目都理解错了,那么错误的输出就可能会因为误解题意而被当成正确的。这个时候是无论如何也de不出bug的。👉👈
-
可以专门为测试写一些方便的方法。比方说在对Bottle的测试时,会因为等级太低携带的瓶子太少而无法测试,因此可以写一个
setLevel(int newLevel)
函数专门用于对处于某一个等级的玩家进行测试。 -
可以为Junit写一个测试模板,毕竟大多数测试都要用到新建玩家、新建药水瓶这一类通用的操作。
三、心得体会
-
审题
一定一定一定要好好审题。我的OOPre作业几乎在每一次作业中都会出现审题问题😂 -
只要需要,就不要吝啬使用变量
第7次作业,我舍友四人全都有9个点没过。最后发现包括我在内的3个人在 c a p a c i t y capacity capacity上犯了很大的错误:让空瓶的 c a p a c i t y capacity capacity为0。这使得购买Bottle
时Bottle
的容量几乎不会有算对的可能(题目对此说的比较隐晦,并没有说明 c a p a c i t y capacity capacity是指瓶子的容积还是液体的体积👀)直到最后才安排上了 i s E m p t y isEmpty isEmpty属性… -
当一个方法需要返回多种值的时候,就尽量不要只用一个方法去实现
比方说使用瓶子的操作(Op12)需要返回使用的瓶子的 i d id id,同时也需要输出玩家的 H i t p o i n t Hitpoint Hitpoint的增加量,当一个方法难以返回两个返回值的的时候,可以试着在调用方法的位置解决,或是分不同方法去解决,也可以试着传递对象的引用(即传对象)去解决。 -
早早重构早早睡觉
老师在最后一节课叫我们反观自己第一节课的代码,然后看看自己的代码究竟有多么不规范,我去看了,然后樂了😂其实这种不规范一方面是来自于真的不会写规范代码,但是我认为更多是**因为迭代次数太小了,前期不知道最终作业时怎么样的,因此无法构建一个能适应后期结构的框架。**所以最好就是在迭代中期就对代码进行重构,重构完会非常舒畅,一次熬夜,一了百了😁毕竟debug也是需要时间的,在有些时候还不如直接重构(这在很多情况下还直接免去了debug的苦恼,因为de不出的bug全被抹掉重写了😋)所以重构这件事真的可以提前几节课说,不一定要细讲,哪怕提一嘴逗号
PS:计组P4第一次写出来,血红色的波形图映射出我惨淡的大二生活,重构一波后直接绿油油的一片😋
四、建议
- 严格审核指导书,对容易产生误解的地方多做说明,及时更正。
- 真的可以给一个比较好的实例给同学们看的,尤其是在强测和bug修复结束之后。现在的OO-Pre课程就有点像: w h i l e ( 1 ) { 写作业 − 交作业 − 系统评测 − 懵逼 − d e b u g − ⋅ ⋅ ⋅ − 通过 } while(1) \{写作业-交作业-系统评测-懵逼-debug- ··· -通过\} while(1){写作业−交作业−系统评测−懵逼−debug−⋅⋅⋅−通过}。就算对了也不一定知道怎么写结构才更好呀。而且给一个可供参考的分析也可以消除很多不必要的误会,更省的同学们去群里和助教们确认一个又一个的问题。我真心觉得可以像数学课物理课学一学,给不了参考答案也至少可以给一个分析吧😖。等到课程结束了再给优秀代码实例是真的难顶——结课了还有谁会去看哪😖