此篇文章接上篇 一个编程小题目引发的思考(上)
其实很多园友已经给出答案了,不过我在这里还是要写一下自己的思路
再把题目叙述一遍
输入:一个小于12位的十进制正整数
输出:打印此数字的十进制计算器表示 例: 输入:145 输出:
__ ||__||__ | | __|于是我又重新思考了一下这道题目,并Review了一下当前的解决方案,发现这个冗长的switch是个很大的问题,这是我想到了代码大全2里提到的表驱动编程方法(就是用一个表来代替冗长的分支控制逻辑)。 小心起见,我从一个方法开始,对其进行了重新组织:
private void PrintTopBody(int value) { if (value != 0) { string[] table = { S1, S0, S1, S1, S0, S1, S1, S1, S1, S1 }; PrintTopBody(value / 10); Console.Write(table[value % 10]); } }测试之后发现运行结果正常,我考虑可以对另外两个方法进行这样的重构,但我发现这样写出的代码依然不好维护,虽然短了很多,但是S1,S0等莫名奇妙的全局变量仍然令人很头疼。 所以接下来就是怎么消除这些恼人的全局字符串常量了。 一时间没想到什么方法,于是又重新运行了一下这个程序,得到了下面的结果:
__ __ __ __ __ __ __ __ | __| __||__||__ |__ ||__||__|| | ||__ __| | __||__| ||__| __||__|这时我突然发现,这个结果不就是一个字符串表吗?为什么不直接利用这个表呢? 于是我打开Regex,利用正则替换,将上面的字符重组为一个二维字符串表格:
private static readonly string[,] TABLE = { {" "," __ "," __ "," "," __ "," __ "," __ "," __ "," __ "," __ "}, {" |"," __|"," __|","|__|","|__ ","|__ "," |","|__|","|__|","| |"}, {" |","|__ "," __|"," |"," __|","|__|"," |","|__|"," __|","|__|"}, };相应的,我新创造了一个LCDPrinter1类,并按照之前的逻辑,编写了对应的方法,代码如下:
class LCDPrinter1 { private static readonly string[,] TABLE = { {" "," __ "," __ "," "," __ "," __ "," __ "," __ "," __ "," __ "}, {" |"," __|"," __|","|__|","|__ ","|__ "," |","|__|","|__|","| |"}, {" |","|__ "," __|"," |"," __|","|__|"," |","|__|"," __|","|__|"}, }; public void PrintNum(int value) { for (int i = 0; i < 3; i++) { PrintOneLayer(value, i); Console.WriteLine(); } } private void PrintOneLayer(int value, int layer) { if (value != 0) { PrintOneLayer(value / 10, layer); Console.Write(TABLE[layer, value % 10]); } } }然后进行测试,我输入123,但惊奇的发现结果是:
__ __ __| __||__| |__ __| |非常像一个off-by-one错误,我看了下字符串表格的定义,原来是0的位置错了,修改之后重新运行,结果正常。 下面是最终的代码:
class LCDPrinter1 { private static readonly string[,] TABLE = { {" __ "," "," __ "," __ "," "," __ "," __ "," __ "," __ "," __ ",}, {"| |"," |"," __|"," __|","|__|","|__ ","|__ "," |","|__|","|__|",}, {"|__|"," |","|__ "," __|"," |"," __|","|__|"," |","|__|"," __|",}, }; public void PrintNum(int value) { for (int i = 0; i < 3; i++) { PrintOneLayer(value, i); Console.WriteLine(); } } private void PrintOneLayer(int value, int layer) { if (value != 0) { PrintOneLayer(value / 10, layer); Console.Write(TABLE[layer, value % 10]); } } }可以发现这个解决方案不但短小(只有25行),而且清晰易懂,逻辑一目了然,相比之前那个150行的解决方案,可谓是天壤之别。