7.3 封装和泛化

6.2 节介绍了一种名为渐进开发的程序编写方法,本节介绍另一种程序开发(program development)流程——封装和泛化,步骤如下。

(1) 在 main 或其他方法中编写几行代码,并进行测试。

(2) 如果能够正确运行,就将它们封装到一个方法中,并再次测试。

(3) 如果这个方法没问题,就将其中的字面量替换为变量和形参。

其中的第二步被称为封装(encapsulation),第 3 步被称为泛化(generalization)。

为演示这种流程,我们将开发几个显示乘法表的方法。下面的循环显示 2 的幂,这些幂值都显示在一行中:

  1. int i = 1;
  2. while (i <= 6) {
  3. System.out.printf("%4d", 2 * i);
  4. i = i + 1;
  5. }
  6. System.out.println();

第 1 行初始化变量 i,这个变量将充当循环变量(loop variable):每次执行循环时,都将变量 i 的值加 1;循环在 i 为 7 后终止。

每次循环都显示 2 * i 的值,并在它前面添加空格,使结果为 4 字符宽。由于我们使用的是 System.out.printf,因此所有输出都显示在一行中。

循环结束后,我们调用 println 打印一个换行符,从而换到下一行。别忘了,输出在有些环境中要遇到换行符后才显示。

因此,上述代码的输出如下:

  1. 2 4 6 8 10 12

下一步是将这些代码“封装”到一个新方法中。这个方法类似于下面这样:

  1. public static void printRow() {
  2. int i = 1;
  3. while (i <= 6) {
  4. System.out.printf("%4d", 2 * i);
  5. i = i + 1;
  6. }
  7. System.out.println();
  8. }

接下来,我们用一个形参 n 替换常量值 2。这一步被称为泛化,因为它让这个方法更通用(不那么具体)。

  1. public static void printRow(int n) {
  2. int i = 1;
  3. while (i <= 6) {
  4. System.out.printf("%4d", n * i);
  5. i = i + 1;
  6. }
  7. System.out.println();
  8. }

如果用实参 2 调用这个方法,得到的输出将与前面相同。使用实参 3 调用这个方法时,输出如下:

  1. 3 6 9 12 15 18

下面是用实参 4 调用这个方法得到的输出:

  1. 4 8 12 16 20 24

至此你可能猜到了我们将如何显示乘法表:反复调用方法 printRow,但每次指定不同的实参。实际上,我们将用另一个循环来遍历所有行。

  1. int i = 1;
  2. while (i <= 6) {
  3. printRow(i);
  4. i = i + 1;
  5. }

输出类似于以下这样:

  1. 1 2 3 4 5 6
  2. 2 4 6 8 10 12
  3. 3 6 9 12 15 18
  4. 4 8 12 16 20 24
  5. 5 10 15 20 25 30
  6. 6 12 18 24 30 36

printRow 中的格式说明符 %4d 确保了输出都是垂直对齐的,不管结果是个位数还是十位数。

最后,我们将第二个循环封装到一个方法中:

  1. public static void printTable() {
  2. int i = 1;
  3. while (i <= 6) {
  4. printRow(i);
  5. i = i + 1;
  6. }
  7. }

编程时面临的挑战之一是如何将程序划分成多个方法,对初学者来说尤其如此。封装和泛化流程能够让你一边编程一边设计。