📢完整的题目要求和源代码请按下面指示前往我的Github仓库~
第二次作业指导书
在本次作业中,我们即将完成面向对象先导课程作业的基础代码编写,在以后的作业中,我们将在本次作业的基础上进行迭代开发。
第一部分:提交要求
请保证提交项目的顶层目录至少存在两个文件夹:src
和test
(命名需严格与此保持一致),请将作业的功能代码存放于src
文件夹下,同时将相关junit测试类代码文件存放于test
文件夹下,以保证评测的正常进行(评测时只会针对src
目录下的文件进行程序功能的评测以及代码风格检测,也就是说,test
目录下的junit测试代码风格不会被检测)。参考目录结构如下:
1 | |-src |
第二部分:题目描述
背景
在接下来的若干次作业中,同学们将进行以本次作业为基础的迭代开发,因此在具体的代码实现中,希望同学们可以考虑到每一次所写代码的可扩展性和可维护性,从而减少下一次的工作量。
在接下来的几次作业中,请想象你是一个穿越到魔法大陆上的冒险者,在旅途中,你需要收集各种道具,使用各种装备,招募其他冒险者加入队伍,提升自己的等级并体验各种战斗。
在本次作业中,你要做的是:
实现冒险者类 Adventurer
、药水瓶类 Bottle
、装备类 Equipment
利用容器,管理所有冒险者,并管理每一个冒险者所拥有的药水瓶和装备
你可能需要实现的类和它们要拥有的属性有:
Adventure :ID,名字,药水瓶和装备各自的容器
Bottle:ID,名字,容量(capacity)
Equipment:ID,名字,星级(star)
请注意,在作业中,可能会存在ID不同但名字相同的情况,请同学们在设计代码的时候考虑这一点
Bottle的容量属性在本次作业中不会被测试,但是却是后续作业的重要部分,请同学们不要忽略。
在本次作业中,初始时,你没有需要管理的冒险者,我们通过若干条操作指令来修改当前的状态:
加入一个需要管理的冒险者(新加入的冒险者不携带任何药水瓶和装备)
给某个冒险者增加一个药水瓶
删除某个冒险者的某个药水瓶
给某个冒险者增加一个装备
删除某个冒险者的某个装备
给某个冒险者的某个装备提升一个星级(星级加1)
输入格式
第一行一个整数 n,表示操作的个数。
接下来的 n 行,每行一个形如 输出数值时,你的输出数值需要和正确数值相等。{type} {attribute}
的操作,{type}
和 {attribute}
间、若干个 {attribute}
间使用若干个空格分割,操作输入形式及其含义如下。同时,为了方便测评,我们需要在需要执行一些指令后进行相关输出。具体要求也在下面的表中列出: 具体要求表
type attribute 意义 输出格式(每条对应的占一行) 1 {adv_id} {name}
加入一个 ID 为 {adv_id}
、名字为 {name}
的冒险者无 2 {adv_id} {bot_id} {name} {capacity}
给 ID 为 {adv_id}
的冒险者增加一个药水瓶,药水瓶的 ID、名字、容量分别为 {bot_id}
、{name}
、{capacity}
无 3 {adv_id} {bot_id}
将 ID 为 {adv_id}
的冒险者的 id 为 {bot_id}
的药水瓶删除{一个整数} {一个字符串}
(解释:整数为删除后冒险者药水瓶数目,字符串为删除的药水瓶的name)4 {adv_id} {equ_id} {name} {star}
给 ID 为 {adv_id}
的冒险者增加一个装备,装备的 ID、名字、星级分别为 {equ_id}
、{name}
、{star}
无 5 {adv_id} {equ_id}
将 ID 为 {adv_id}
的冒险者的 id 为 {equ_id}
的装备删除{一个整数} {一个字符串}
(解释:整数为删除后冒险者装备数目,字符串为删除的装备的name)6 {adv_id} {equ_id}
将 ID 为 {adv_id}
的冒险者的 id 为 {equ_id}
的装备提升一个星级{一个字符串} {一个整数}
(解释:字符串为装备的name,整数为装备升星后的星级)
样例
1 | 4 |
期望输出
1 | ?TE/G1 4 |
1 | 3 |
期望输出
1 | 0 ?TE/G1 |
数据限制
变量约束
变量约束
变量 | 类型 | 说明 |
---|---|---|
id | 整数 | 取值范围:0 - 2147483647 |
name | 字符串 | 保证不会出现空白字符,长度区间: (0,40) |
capacity | 整数 | 取值范围:0 - 2147483647 |
star | 整数 | 取值范围:0 - 2147483647 |
操作约束
操作约束
- 保证所有的冒险者、药水瓶、装备 id 均不相同
- 保证删除了的药水瓶/装备的 id 不会再次出现
- 2-6保证所有冒险者均已存在
- 3/5/6保证该冒险者拥有操作中提到 id 的药水瓶/装备
- 保证增加的装备和药水瓶原本不存在
- 操作数满足1≤n≤2000
junit测试
我们在gitlab上准备了一份junit使用示例代码(基于hw1程序)以及一份junit使用文档供大家参考,推荐各位同学在课下测试时使用 junit 单元测试来对自己的程序进行测试
junit 是一个单元测试包,可以通过编写单元测试类和方法,来实现对类和方法实现正确性的快速检查和测试。还可以查看测试覆盖率以及具体覆盖范围(精确到语句级别),以帮助编程者全面无死角地进行程序功能测试。
此外,Junit 对主流 Java IDE(Idea、eclipse 等)均有较为完善的支持,具体的配置和使用方法可以参考gitlab上的使用文档。
要求
本次作业要求同学们需要自行编写junit测试代码对自己的代码进行测试。在本次作业中,检测到存在junit测试方法并可以成功编译即视为通过junit评测。
解析说明
关于第二次作业的解析与说明
第二次作业开始正式迭代开发,本次作业难度一般,主要目标是编写基础代码准备接下来几周的迭代与扩展。
注意:划删除线的部分并非过时信息!
Part 1
指导书的大致要求是:
实现以下类
1 | Adventure :ID,名字,药水瓶和装备各自的容器 |
以及实现以下操作
1 | 1.加入一个需要管理的冒险者(新加入的冒险者不携带任何药水瓶和装备) |
并且做了一些约束使问题简化,这里不再赘述。
我认为本次作业主要考虑三点:
如何用合适的容器对Adventure类、Bottle类以及Equipment类进行管理
上述三个类的内部结构如何实现
如何实现同时返回一个字符串和整数信息
对于第一点,我一开始的思路是,用ArrayList来管理三个类,这是一种很自然的想法。但是,在随后的具体实现中,我发现很多操作要求通过ID来获取对象,而由于ID属性被封装在各个类中,以我的水平只能对ArrayList遍历来查找需要的冒险者、药瓶或者是装备。
这样带来的坏处是,需要自己实现遍历查找算法,而且遍历效率极低。同时checkstyle还会提示for循环部分重复度过高(查找Bottle和Equipment时有大量重复结构)。
那么,有没有更好的改进办法呢?我想到了下面的思路:
利用每个对象ID属性的唯一性,用ID作为Key,相应对象(Adventure类、Bottle类以及Equipment类)做为Value,构建HashMap来进行管理。
也就是如下三个容器:
1 | HashMap<Integer, Adventure> adventures = new HashMap<>(); |
这样的好处是,HashMap类本身已经提供了通过Key快速查找Value的方法,而且代码简洁,checkstyle也不会提示重复度过高的问题。可谓一举两得。
有了第一点的思路,各个类的内部结构也就比较清晰,以功能最多的Adventure类为例,应该如下:
1 | //属性 |
在java中,一个方法或者函数只能返回一个对象,那么如何同时返回一个字符串和整数呢?
一开始,我同样想用HashMap,但是又遇到问题:我们每次只需要一个Key-Value对,为此单独构造一个容器似乎没有必要,而且这也没有体现Key和Value的映射关系。
因此经过考虑,我自定义了一个工具类PrintInfo,能根据一个整数值和字符串值构造对象,并提供不同顺序的打印方法。
1 | public class PrintInfo { |
这样 负责删除且需要返回结果的方法便可以声明返回该类型。
解决了这三个问题,Part 1的要求相信很快就能解决。
Part 2
本次作业Part 2要求不高,自行阅读文档,了解JUnit类的使用即可。
题目信息