题目内容:
说明
题目内容 有一名体育老师,在某次离下课还有五分钟时,决定玩一个报数游戏。此时有100名学生在上课,游戏的规则如下:
在开始做题之前,先问一下自己几个问题:
这里我就不鼓吹单元测试有多么好,能带来什么好处。一切都以结果为导向,笔者也是本着学习的心态,跟着大神们去领略代码之美,让自己也能写出健壮的代码,告别996(OS:虽然我现在也没有996)。
先花5~10分钟理解题目,基本能知道这是个报数游戏,我们输入一个数字,让它输出是结果有4种:
如果对代码没有要求的话,我们最开始可能会写很多if else的代码,例如下面代码:
public class FizzBuzz {
public static void sayNumberGame(int firstNum, int secondNum) {
// 从1~100报数
for (int i = 1; i <= 100; i++) {
// 即是第一个特殊数字的倍数又是第二个数字的倍数说FizzBuzz
if (isMultipleNum(firstNum, i) && isMultipleNum(secondNum, i)) {
System.out.println(String.format("%s Don't Say number, but say FizzBuzz", i));
continue;
}
// 第一个特殊数字的倍数说Fizz
if (isMultipleNum(firstNum, i)) {
System.out.println(String.format("%d is a multiple of %d or contains %d Say Fizz", i, firstNum, firstNum));
continue;
}
// 第二个特殊数字的倍数说Buzz
if (isMultipleNum(secondNum, i)) {
System.out.println(String.format("%d is a multiple of %d or contains %d Say Buzz", i, secondNum, secondNum));
continue;
}
// 不满足以上所有条件
System.out.println(String.format("%s Say number", i));
}
}
public static boolean isMultipleNum(int targetNum, int sayNum) {
String targetNumStr = String.valueOf(targetNum);
String sayNumStr = String.valueOf(sayNum);
return sayNum % targetNum == 0 || sayNumStr.contains(targetNumStr);
}
public static void main(String[] args) {
System.out.println("00.FizzBuzz!!!");
sayNumberGame(3, 5);
}
}
上面代码有什么问题?
这次我先写测试,将不同情况的输出分别写了测试方法来验证:
public class FizzBuzzTest {
@Test
public void testSayFizz() {
assertEquals("Fizz", FizzBuzz.fizzBuzz(3, 3, 5));
}
@Test
public void testSayBuzz() {
assertEquals("Buzz", FizzBuzz.fizzBuzz(5, 3, 5));
}
@Test
public void testSayFizzBuzz() {
assertEquals("FizzBuzz", FizzBuzz.fizzBuzz(15, 3, 5));
}
@Test
public void testOnlySayNum() {
assertEquals("1", FizzBuzz.fizzBuzz(1, 3, 5));
}
}
注:这里我用的IDE是Intellij,测试框架用的是Junit4.
代码我也进行了重构:
public class FizzBuzz {
private static final String FIZZBUZZ = "FizzBuzz";
private static final String FIZZ = "Fizz";
private static final String BUZZ = "Buzz";
public static String fizzBuzz(int sayNum, int firstNum, int secondNum) {
// 即是第一个特殊数字的倍数又是第二个数字的倍数说FizzBuzz
if (isFizzBuzz(sayNum, firstNum, secondNum)) {
return FIZZBUZZ;
}
// 第一个特殊数字的倍数说Fizz
if (isFizz(sayNum, firstNum)) {
return FIZZ;
}
// 第二个特殊数字的倍数说Buzz
if (isBuzz(sayNum, secondNum)) {
return BUZZ;
}
// 不满足以上所有条件
return String.valueOf(sayNum);
}
public static boolean isFizzBuzz(int sayNum, int firstNum, int secondNum) {
return isFizz(sayNum, firstNum) && isBuzz(sayNum, secondNum);
}
public static boolean isFizz(int sayNum, int targetNum) {
return isMultipleOrContainNum(sayNum, targetNum);
}
public static boolean isBuzz(int sayNum, int targetNum) {
return isMultipleOrContainNum(sayNum, targetNum);
}
public static boolean isMultipleOrContainNum(int sayNum, int targetNum) {
return (sayNum % targetNum == 0 || formatNumToString(sayNum).contains(formatNumToString(targetNum)));
}
public static String formatNumToString(int num) {
return String.valueOf(num);
}
}
可以看到重构后的代码已经差别很大,但可测性明显提升了不少,基本可以从方法名表达意图,可读性也提升了。
最后自然是全绿通过: