需求背景
请你设计一个计算保龄球比赛一局总得分的程序,保龄球的计分规则如下:
- 每一局总共有十轮,每轮一开始会有十支球瓶,球手可以扔两次球,目标就是用尽量少的球把全部球瓶击倒。
- 如果第一球就把全部的球瓶都击倒了,也就是STRIKE,画面出现“X”,就算完成一轮了,所得分数是10分再加后面两球的倒瓶数。
- 如果第一球没有全倒,就要再打一球,如果第二球将剩下的球瓶全都击倒,也就是SPARE,画面出现“/”,也算完成一格,所得分数为10分再加下一轮第一球的倒瓶数。
- 如果第二球也没有把球瓶全部击倒的话,那分数就是第一球加第二球倒的瓶数,没有奖励(bonus),再接着打下一轮。依此类推。
- 第十轮有机会扔三次球。如果在第十轮出现STRIKE或者SPARE,则球手可再加打第三球。
- 全部十轮的得分相加就等于这一局的总得分。

需求分析
拿到需求后,第一个件重要的事情永远都是理解需求,第二件重要的事情是拆分需求。
通读业务描述,分析出系统要解决的核心业务问题是为每一局统计总分,这就是系统将提供面向用户的端到端功能。最终的需求分解始终应该聚焦在这个点上,要避免陷入某一轮的细节中。
每一局游戏又分为10轮,最终的总分是根据一局比赛中每轮中每次击倒的瓶数,按照一定的业务与规则计算出来。所以,为了统计每局结束后的总分,系统还要能够记录每次击倒瓶数,从而为统计总得分提供数据。
到此,我们识别出系统需要提供的核心功能是统计总分,还需要有一个功能是能够记录每次击球数。
从需求描述中得到信息,每一轮中的倒瓶数的规则会对总分产生不同的影响,对于某一轮,有如下几种场景:
- 某轮中,两次扔球都没有碰到球,所得分数为0。
- 某轮中,两次扔球都没有将球瓶全部击倒,所得分数为两球的倒瓶数。
- 某轮中,第一球就把全部的球瓶都击倒,STRIKE,所得分数是10分再加后面两球的倒瓶数。
- 某轮中,第二球将剩下的全部球品击倒,SPARE,所得分数为10分再加下一轮第一球的倒瓶数。
其实场景1是场景2的极端情况,我回想起了当年第一次玩保龄球的时候,就出现过这种情况,所以我很快就想到了它。
经过上述分析,每一轮得分将被分成四类。此时,你可能会问,这只是1轮的4种场景,如果统计10轮的总得分,如果穷举出来,是不是应该得有4^10 = 1,048,576种业务场景(一个极端负责人的QA或许会想办法去测试这么多场景,此QA能用程序生成测试数据~ ~)。理论上,这样穷举出来的结果就是现实中真实存在的全部场景。这样去拆分业务需求,本身是没有错的,但看到这个数字,还没有开始写测试,估计你内心就已经崩盘了。
英雄难过Tasking关,TDD的践行显然无望了。为了拯救英雄,我们需要进一步业务抽象。多琢磨琢磨,其实10轮只是1轮的重复,如果我们确保了每1轮的统计是正确的就好,然后将每1轮循环运用到这10轮中,是否能确保最终的计分功能是可靠的?
答案是:肯定的 (软件将通过合理的抽象建模来解决现实中复杂的业务问题)
通过进一步业务抽象,结合我们识别出来的系统核心端到端功能,我们对进行业务拆分如下的几种场景:
- 每一轮的两次扔球都没有碰到球,所得分数为0。
- 每一轮的两次扔球都没有全部击倒球瓶,所得分数为每次扔球的倒瓶数总和。
- 存在一轮SPARE,所得分数为每次扔球的倒瓶数总和再加SPARE轮后的一球的倒瓶数。
- 存在一轮STRIKE,所得分数为每次扔球的倒瓶数总和再加STRIKE轮后两球的倒瓶数。
- 十轮均为STRIKE,所得分数300。
网友评论