目錄請見:模塊化(零):綜述
第 1 步:修改變量名
如果你改的是自己的代碼,可以暫時不做這一步,跳到第二步。(畢竟你 現在暫時 還能看得懂前幾天寫的代碼)
從初始代碼可以看出,很多變量名不合適。例如:
int useNo = 0;// 控制操作符
這里的 useNo 用于控制是否能生成乘號和除號。通過 useNo 你無法知道這個變量名表示什么,就算你看了這行后面的注釋,你也不知道這個變量是用來干嘛的。
這一行一開始被我改成:
int baseNum = 0; // 控制操作符是否能為乘號和除號
控制符號是否能為乘除號的代碼是這樣的(三個點表示省略中間的代碼):
char[] op = { ' ', '+', '-', '*', '÷' };
...
if (useMultiAndDiv == 'Y' || useMultiAndDiv == 'y') {
baseNum = 4;
} else if (useMultiAndDiv == 'N' || useMultiAndDiv == 'n') {
baseNum = 2;
}
...
opIndex[k] = (int) (Math.random() * baseNum + 1);
...
switch(op[opIndex[g]){
...
這里使用 baseNum 作為基數,Math.random() 生成 0.0 到 1.0 之間的數。如果 baseNum 等于2,那么隨機出來的數乘以基數后最大為2,因此無法取到乘號和除號。
在不對源代碼進行較大改動的情況下,我能想到的最合適命名就是 baseNum 了。搭配代碼之后的注釋,讀者應該比較容易理解。
變量名不是主角,就不講太多了。
變量名重新命名后的代碼:
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.Scanner;
public class lastdemo {
/**
* 求兩個整數的最大公約數
*
* @param num1
* @param num2
* @return num1 和 num2 的最大公約數
*/
private static int Gcd(int num1, int num2) {
num1 = Math.abs(num1);
num2 = Math.abs(num2);
int min = Math.min(num1, num2);
int maxSubmultiple = 1;
for (int i = min; i >= 1; i--) {
if (num1 % i == 0 && num2 % i == 0) {
maxSubmultiple = i;
break;
}
}
return maxSubmultiple;
}
public static void main(String[] args) {
Scanner inputs = new Scanner(System.in);
System.out.print("請輸入你想要作答的題目數量:");
int problemsCount = inputs.nextInt();
System.out.print("請選擇你要進行的運算:1.整數;2.真分數;");
int choice = inputs.nextInt();
if (choice == 1) {
double rightCount = 0;
for (int i = 1; i <= problemsCount; i++) {
int leftNum = (int) (Math.random() * 10 + 1);/* 防止出現不好處理的0,很不嚴謹不可取 */
int rightNum = (int) (Math.random() * 10 + 1);
int result = 0;
int operator = (int) (Math.random() * 4);
switch (operator) {
case 0:
System.out.print("第" + i + "題" + ": ");
System.out.print(leftNum + " + " + rightNum + " = ");
result = leftNum + rightNum;
break;
case 1:
if (leftNum < rightNum) {
int t = leftNum;
leftNum = rightNum;
rightNum = t;
}
System.out.print("第" + i + "題" + ": ");
System.out.print(leftNum + " - " + rightNum + " = ");
result = leftNum - rightNum;
break;
case 2:
System.out.print("第" + i + "題" + ": ");
System.out.print(leftNum + " × " + rightNum + " = ");
result = leftNum * rightNum;
break;
case 3:
System.out.print("第" + i + "題" + ": ");
if (leftNum < rightNum) {
int t = leftNum;
leftNum = rightNum;
rightNum = t;
}
if (leftNum % rightNum != 0) {
leftNum = (int) (Math.random() * 10 + 1) * rightNum;/* 保證能整除 */
}
System.out.print(leftNum + " ÷ " + rightNum + " = ");
result = leftNum / rightNum;
break;
}
int answer = inputs.nextInt();
if (answer == result) {
rightCount++;
System.out.println("答對了,恭喜\n");
} else {
System.out.println("答錯了,加油\n");
}
}
System.out.println("True Rate:" + rightCount / problemsCount);
} else if (choice == 2) {
final int OP_MAX = 4;
char[] op = {' ', '+', '-', '*', '÷'};
int[] opIndex = new int[OP_MAX]; // 保存操作符下標
int baseNum = 0; // 控制操作符是否能為乘號和除號
boolean shouldOutputOp = true;
int[] nums = new int[4];
final int PROBLEMS_COUNT_MAX = 100;
String[] userAnswer = new String[PROBLEMS_COUNT_MAX];
String[] standardAnswer = new String[PROBLEMS_COUNT_MAX];
DecimalFormat decimal = new DecimalFormat("#.##");
decimal.setRoundingMode(RoundingMode.HALF_UP);
int leftNumerator;
int rightNumerator;
int resultDenominator;
int resultNumerator;
int gcd; // 最大公約數
boolean isDividedByZero = false;
boolean isMultipliedByZero = false;
String simplestNumerator = "";
String simplestDenominator = "";
System.out.print("請選擇是否需要乘除法算術題(Y or N):");
char useMultiAndDiv = inputs.next().charAt(0);
if (useMultiAndDiv == 'Y' || useMultiAndDiv == 'y') {
baseNum = 4;
} else if (useMultiAndDiv == 'N' || useMultiAndDiv == 'n') {
baseNum = 2;
}
System.out.println("請計算下列真分數計算題。(若無法運算請填入null)");
System.out.println("***************************************");
final int MAX_NUM = 10;
final int MIN_NUM = 1;
for (int i = 0; i < problemsCount; i++) {
System.out.print("(" + (i + 1) + ") ");
// 第一個真分數。nums[0]為分子,nums[1]為分母
for (int index = 0; index < 2; index++) {
nums[index] = (int) (Math.random()
* (MAX_NUM - MIN_NUM) + MIN_NUM);
if (index == 1) {
// 保證分子不大于分母,以及分母不為零
while (nums[index - 1] > nums[index] || nums[index] == 0) {
nums[index] = (int) (Math.random()
* (MAX_NUM - MIN_NUM) + MIN_NUM);
}
}
}
// 第二個真分數。nums[2]為分子,nums[3]為分母
for (int index = 2; index < 4; index++) {
nums[index] = (int) (Math.random()
* (MAX_NUM - MIN_NUM) + MIN_NUM);
if (index == 3) {
// 保證分子不大于分母,以及分母不為零
while (nums[index - 1] > nums[index] || nums[index] == 0) {
nums[index] = (int) (Math.random()
* (MAX_NUM - MIN_NUM) + MIN_NUM);
}
}
}
// 產生兩個操作符下標。乘以2最多得2
for (int index = 0; index < 2; index++) {
opIndex[index] = (int) (Math.random() * baseNum + 1);
}
// 輸出整個式子,index 表示正在輸出的數字的位置
for (int index = 0; index < 4; index++) {
if (index % 2 == 0) {
System.out.print("(" + nums[index] + "/");
} else if (index % 2 == 1) {
System.out.print(nums[index] + ")");
if (shouldOutputOp) {
System.out.print(op[opIndex[0]]);
shouldOutputOp = false;
} else {
System.out.println("=");
}
}
}
shouldOutputOp = true;
// 求結果
for (int index = 0; index < 1; index++) {
// 不求最大公倍數,直接乘對方分母
resultDenominator = nums[1] * nums[3];
leftNumerator = nums[0] * nums[3];
rightNumerator = nums[2] * nums[1];
isDividedByZero = false;
isMultipliedByZero = false;
switch (op[opIndex[index]]) {
case '+':
resultNumerator = leftNumerator + rightNumerator;
gcd = Gcd(resultNumerator, resultDenominator);
simplestNumerator = String.valueOf(resultNumerator / gcd);
simplestDenominator = String.valueOf(resultDenominator / gcd);
break;
case '-':
resultNumerator = leftNumerator - rightNumerator;
gcd = Gcd(resultNumerator, resultDenominator);
simplestNumerator = String.valueOf(resultNumerator / gcd);
simplestDenominator = String.valueOf(resultDenominator / gcd);
break;
case '*':
resultNumerator = nums[0] * nums[2];
gcd = Gcd(resultNumerator, resultDenominator);
// 分子有0則結果為0
if (nums[0] == 0 || nums[2] == 0) {
isMultipliedByZero = true;
}
simplestNumerator = String.valueOf(resultNumerator / gcd);
simplestDenominator = String.valueOf(resultDenominator / gcd);
break;
case '/':
// 除以一個數,等于乘以它的倒數
resultNumerator = nums[0] * nums[3];
resultDenominator = nums[1] * nums[2];
gcd = Gcd(resultNumerator, resultDenominator);
if (nums[0] == 0 || nums[2] == 0) {
isDividedByZero = true;
}
simplestNumerator = String.valueOf(resultNumerator / gcd);
simplestDenominator = String.valueOf(resultDenominator / gcd);
break;
}
}
if (isDividedByZero) {
standardAnswer[i] = "null"; // 當第二個數的分子為零時無法進行除法運算
} else if (isMultipliedByZero) {
standardAnswer[i] = "0";
} else if (simplestNumerator.equals(simplestDenominator)) {
standardAnswer[i] = "1";
} else if (simplestDenominator.equalsIgnoreCase("1")) {
standardAnswer[i] = simplestNumerator;
} else {
standardAnswer[i] = simplestNumerator + "/" + simplestDenominator;
}
}
// 用戶答題
int rightCount = 0;
System.out.println("請輸入你的答案:");
for (int i = 0; i < problemsCount; i++) {
System.out.print((i + 1) + ":");
userAnswer[i] = inputs.next();
if (userAnswer[i].equals(standardAnswer[i])) {
rightCount++;
}
}
System.out.println("標準答案是 : ");
for (int i = 0; i < problemsCount; i++) {
System.out.println((i + 1) + ":" + standardAnswer[i]);
}
double trueRate = ((double) rightCount / (double) problemsCount) * 100;
System.out.println("True rate:" + decimal.format(trueRate) + "%");
System.out.println("**************************************");
} else {
System.out.println("請輸入1或2:");
}
}
}
第 2 步:標記模塊
在讀懂代碼的基礎上,標出代碼運行中每個步驟都做了什么。我在這里特別標出了各個分支的等級和分支號。等級從外到內遞增,分支號從上到下遞增。
在 (等級一)選擇分支二
中有個 for 循環。它的代碼太長,我在結尾處加上了一個注釋:
// 輸出題目并計算題目的答案
...
for (int i = 0; i < problemsCount; i++) {
...
} // 輸出題目并計算答案結束
你可能要拉 3 - 4 個屏幕才能看到。
在一段很長的代碼中,會有幾個比較大的功能塊,可以將其理解為一臺機器的 "零件"。
還是以 (等級一)選擇分支二
為例,標記結束并整理如下:
- 初始化用戶答案和標準答案數組
- 讓用戶選擇是否出乘除法的題目
- 生成題目并輸出,還有計算答案 的 for 循環
- 生成第一個真分數
- 生成第二個真分數
- 隨機獲取兩個運算符的坐標
- 輸出整個式子
- 求式子的標準答案
- 加法的情況
- 減法的情況
- 乘法的情況
- 除法的情況
- 根據標準答案的計算情況選擇標準答案的正確形式
- 獲取用戶輸入的答案、與標準答案比較
- 輸出標準答案
- 計算并輸出正確率
這里的每一項基本都能抽成一個模塊。
以下是標記完模塊后的代碼:
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.Scanner;
public class LastDemo {
/**
* 求兩個整數的最大公約數
*
* @param num1
* @param num2
* @return num1 和 num2 的最大公約數
*/
private static int Gcd(int num1, int num2) {
num1 = Math.abs(num1);
num2 = Math.abs(num2);
int min = Math.min(num1, num2);
int maxSubmultiple = 1;
for (int i = min; i >= 1; i--) {
if (num1 % i == 0 && num2 % i == 0) {
maxSubmultiple = i;
break;
}
}
return maxSubmultiple;
}
public static void main(String[] args) {
// 入口控制,基本輸入
Scanner inputs = new Scanner(System.in);
System.out.print("請輸入你想要作答的題目數量:");
int problemsCount = inputs.nextInt();
System.out.print("請選擇你要進行的運算:1.整數;2.真分數;");
int choice = inputs.nextInt();
// (等級一)選擇分支一
if (choice == 1) {
int rightCount = 0;
for (int i = 1; i <= problemsCount; i++) {
int leftNum = (int) (Math.random() * 10 + 1);/* 防止出現不好處理的0,很不嚴謹不可取 */
int rightNum = (int) (Math.random() * 10 + 1);
int result = 0;
// 根據隨機的運算符進行相應的操作
int operator = (int) (Math.random() * 4);
switch (operator) {
case 0:
// (等級二)選擇分支一
System.out.print("第" + i + "題" + ": ");
System.out.print(leftNum + " + " + rightNum + " = ");
result = leftNum + rightNum;
break;
case 1:
// (等級二)選擇分支二
if (leftNum < rightNum) {
int t = leftNum;
leftNum = rightNum;
rightNum = t;
}
System.out.print("第" + i + "題" + ": ");
System.out.print(leftNum + " - " + rightNum + " = ");
result = leftNum - rightNum;
break;
case 2:
// (等級二)選擇分支三
System.out.print("第" + i + "題" + ": ");
System.out.print(leftNum + " × " + rightNum + " = ");
result = leftNum * rightNum;
break;
case 3:
// (等級二)選擇分支四
System.out.print("第" + i + "題" + ": ");
if (leftNum < rightNum) {
int t = leftNum;
leftNum = rightNum;
rightNum = t;
}
// 保證能整除
if (leftNum % rightNum != 0) {
leftNum = (int) (Math.random() * 10 + 1) * rightNum;
}
System.out.print(leftNum + " ÷ " + rightNum + " = ");
result = leftNum / rightNum;
break;
}
// 獲取用戶輸入并判斷
int answer = inputs.nextInt();
if (answer == result) {
rightCount++;
System.out.println("答對了,恭喜\n");
} else {
System.out.println("答錯了,加油\n");
}
}
System.out.println("True Rate:" + (double) rightCount / problemsCount);
} else if (choice == 2) {
// (等級一)選擇分支二
final int PROBLEMS_COUNT_MAX = 100;
String[] userAnswer = new String[PROBLEMS_COUNT_MAX];
String[] standardAnswer = new String[PROBLEMS_COUNT_MAX];
// 是否出現乘除法的題目
System.out.print("請選擇是否需要乘除法算術題(Y or N):");
char useMultiAndDiv = inputs.next().charAt(0);
int baseNum = 0; // 控制操作符是否能為乘號和除號
if (useMultiAndDiv == 'Y' || useMultiAndDiv == 'y') {
baseNum = 4;
} else if (useMultiAndDiv == 'N' || useMultiAndDiv == 'n') {
baseNum = 2;
}
System.out.println("請計算下列真分數計算題。(若無法運算請填入null)");
System.out.println("***************************************");
// 輸出題目并計算題目的答案
final int MAX_NUM = 10;
final int MIN_NUM = 1;
int[] nums = new int[4];
for (int i = 0; i < problemsCount; i++) {
System.out.print("(" + (i + 1) + ") ");
// 第一個真分數。nums[0]為分子,nums[1]為分母
for (int index = 0; index < 2; index++) {
nums[index] = (int) (Math.random()
* (MAX_NUM - MIN_NUM) + MIN_NUM);
if (index == 1) {
// 保證分子不大于分母,以及分母不為零
while (nums[index - 1] > nums[index] || nums[index] == 0) {
nums[index] = (int) (Math.random()
* (MAX_NUM - MIN_NUM) + MIN_NUM);
}
}
}
// 第二個真分數。nums[2]為分子,nums[3]為分母
for (int index = 2; index < 4; index++) {
nums[index] = (int) (Math.random()
* (MAX_NUM - MIN_NUM) + MIN_NUM);
if (index == 3) {
// 保證分子不大于分母,以及分母不為零
while (nums[index - 1] > nums[index] || nums[index] == 0) {
nums[index] = (int) (Math.random()
* (MAX_NUM - MIN_NUM) + MIN_NUM);
}
}
}
final int OP_MAX = 4;
int[] opIndex = new int[OP_MAX]; // 保存操作符下標
// 產生兩個操作符下標。乘以2最多得2
for (int index = 0; index < 2; index++) {
opIndex[index] = (int) (Math.random() * baseNum + 1);
}
char[] op = {' ', '+', '-', '*', '÷'};
// 輸出整個式子,index 表示正在輸出的數字的位置
boolean shouldOutputOp = true;
for (int index = 0; index < 4; index++) {
if (index % 2 == 0) {
System.out.print("(" + nums[index] + "/");
} else if (index % 2 == 1) {
System.out.print(nums[index] + ")");
if (shouldOutputOp) {
System.out.print(op[opIndex[0]]);
shouldOutputOp = false;
} else {
System.out.println("=");
}
}
}
// 求結果
int leftNumerator;
int rightNumerator;
int resultDenominator;
int resultNumerator;
int gcd; // 最大公約數
boolean isDividedByZero = false;
boolean isMultipliedByZero = false;
String simplestNumerator = "";
String simplestDenominator = "";
// 不求最大公倍數,直接乘對方分母
resultDenominator = nums[1] * nums[3];
leftNumerator = nums[0] * nums[3];
rightNumerator = nums[2] * nums[1];
switch (op[opIndex[0]]) {
case '+':
// (等級二)選擇分支一
resultNumerator = leftNumerator + rightNumerator;
gcd = Gcd(resultNumerator, resultDenominator);
simplestNumerator = String.valueOf(resultNumerator / gcd);
simplestDenominator = String.valueOf(resultDenominator / gcd);
break;
case '-':
// (等級二)選擇分支二
resultNumerator = leftNumerator - rightNumerator;
gcd = Gcd(resultNumerator, resultDenominator);
simplestNumerator = String.valueOf(resultNumerator / gcd);
simplestDenominator = String.valueOf(resultDenominator / gcd);
break;
case '*':
// (等級二)選擇分支三
resultNumerator = nums[0] * nums[2];
gcd = Gcd(resultNumerator, resultDenominator);
// 分子有0則結果為0
if (nums[0] == 0 || nums[2] == 0) {
isMultipliedByZero = true;
}
simplestNumerator = String.valueOf(resultNumerator / gcd);
simplestDenominator = String.valueOf(resultDenominator / gcd);
break;
case '/':
// (等級二)選擇分支四
// 除以一個數,等于乘以它的倒數
resultNumerator = nums[0] * nums[3];
resultDenominator = nums[1] * nums[2];
gcd = Gcd(resultNumerator, resultDenominator);
if (nums[0] == 0 || nums[2] == 0) {
isDividedByZero = true;
}
simplestNumerator = String.valueOf(resultNumerator / gcd);
simplestDenominator = String.valueOf(resultDenominator / gcd);
break;
}
if (isDividedByZero) {
standardAnswer[i] = "null"; // 當第二個數的分子為零時無法進行除法運算
} else if (isMultipliedByZero) {
standardAnswer[i] = "0";
} else if (simplestNumerator.equals(simplestDenominator)) {
standardAnswer[i] = "1";
} else if (simplestDenominator.equalsIgnoreCase("1")) {
standardAnswer[i] = simplestNumerator;
} else {
standardAnswer[i] = simplestNumerator + "/" + simplestDenominator;
}
} // 輸出題目并計算答案結束
// 用戶答題
int rightCount = 0;
System.out.println("請輸入你的答案:");
for (int i = 0; i < problemsCount; i++) {
System.out.print((i + 1) + ":");
userAnswer[i] = inputs.next();
if (userAnswer[i].equals(standardAnswer[i])) {
rightCount++;
}
}
System.out.println("標準答案是 : ");
for (int i = 0; i < problemsCount; i++) {
System.out.println((i + 1) + ":" + standardAnswer[i]);
}
DecimalFormat decimal = new DecimalFormat("#.##");
decimal.setRoundingMode(RoundingMode.HALF_UP);
double trueRate = ((double) rightCount / (double) problemsCount) * 100;
System.out.println("True rate:" + decimal.format(trueRate) + "%");
System.out.println("**************************************");
} else {
// (等級一)判斷分支三:輸入非指定選項
System.out.println("請輸入1或2:");
}
}
}
第 3 步:把標記的每個部分抽取到新的方法里
新創建的方法要盡量滿足以下兩個條件:
- 方法內不能直接使用全局變量。如果要使用外部的變量,使用參數傳遞;
- 每個方法在處理完一件事之后,使用 return 返回結果。
也就是說,把新創建的方法放在任何一個地方都不會編譯錯誤。
3.1 先干掉大家伙
標記 (等級一)選擇分支一
和 (等級一)選擇分支二
分別表示整數的處理和真分數的處理。它們是在一塊 if- else if - else
的分支結構中。
在某一個分支下,不應該有太多的代碼。如果實在需要很多代碼才能完成功能,那么就創建轉發函數(方法)。
分析兩個分支代碼:
- 輸入部分
仔細看一遍上面的代碼,你會發現這兩個分支只用到存在于分支外的一個變量problemsCount
。換句話說,分支只依賴于一個輸入problemsCount
。 - 輸出部分
在每一個選擇分支結束后,程序就結束了,沒有其他處理。這里就不需要返回任何值。
分析完輸入輸出之后,創建空方法:
private static void IntegerMode(int problemsCount) {
}
private static void FractionMode(int problemsCount) {
}
接著將標記為 (等級一)選擇分支一
和 (等級一)選擇分支二
的兩塊代碼分別放入以上的 IntegerMode(int)
和 FractionMode(int)
里面。
這時候原來的分支就變成這樣:
if (choice == 1) {
} else if (choice == 2) {
} else {
// (等級一)判斷分支三:輸入非指定選項
System.out.println("請輸入1或2:");
}
此時在分支里面填上相應的轉發函數。
public static void main(String[] args) {
// 入口控制,基本輸入
Scanner inputs = new Scanner(System.in);
System.out.print("請輸入你想要作答的題目數量:");
int problemsCount = inputs.nextInt();
System.out.print("請選擇你要進行的運算:1.整數;2.真分數;");
int choice = inputs.nextInt();
if (choice == 1) {
IntegerMode(problemsCount);
} else if (choice == 2) {
FractionMode(problemsCount);
} else {
// (等級一)判斷分支三:輸入非指定選項
System.out.println("請輸入1或2:");
}
}
至此,我們將 222 行的 main() 方法壓縮到了 19 行。現在 main() 方法做了哪些事已經很清楚了。
但是還沒結束,新創建的 IntegerMode(int)
和 FractionMode(int)
代碼行數分別為 63 行和 172 行。
軟件工程師通常一次只能看到 30-80 行源代碼(相當于顯示器的一屏) —— 《構建之法》第二版p23
我的小分辨率屏幕只能顯示 30 行左右的代碼。一旦一塊代碼超出這個數,就會對閱讀代碼的人造成一定的影響。
3.2 開始處理真分數模式
既然 FractionMode(int)
的行數比較多(172行),那么就幫它減肥吧!
以下是它的完整代碼:
private static void FractionMode(int problemsCount) {
final int PROBLEMS_COUNT_MAX = 100;
String[] userAnswer = new String[PROBLEMS_COUNT_MAX];
String[] standardAnswer = new String[PROBLEMS_COUNT_MAX];
// 是否出現乘除法的題目
System.out.print("請選擇是否需要乘除法算術題(Y or N):");
Scanner inputs = new Scanner(System.in);
char useMultiAndDiv = inputs.next().charAt(0);
int baseNum = 0; // 控制操作符是否能為乘號和除號
if (useMultiAndDiv == 'Y' || useMultiAndDiv == 'y') {
baseNum = 4;
} else if (useMultiAndDiv == 'N' || useMultiAndDiv == 'n') {
baseNum = 2;
}
System.out.println("請計算下列真分數計算題。(若無法運算請填入null)");
System.out.println("***************************************");
// 輸出題目并計算題目的答案
final int MAX_NUM = 10;
final int MIN_NUM = 1;
int[] nums = new int[4];
for (int i = 0; i < problemsCount; i++) {
System.out.print("(" + (i + 1) + ") ");
// 第一個真分數。nums[0]為分子,nums[1]為分母
for (int index = 0; index < 2; index++) {
nums[index] = (int) (Math.random()
* (MAX_NUM - MIN_NUM) + MIN_NUM);
if (index == 1) {
// 保證分子不大于分母,以及分母不為零
while (nums[index - 1] > nums[index] || nums[index] == 0) {
nums[index] = (int) (Math.random()
* (MAX_NUM - MIN_NUM) + MIN_NUM);
}
}
}
// 第二個真分數。nums[2]為分子,nums[3]為分母
for (int index = 2; index < 4; index++) {
nums[index] = (int) (Math.random()
* (MAX_NUM - MIN_NUM) + MIN_NUM);
if (index == 3) {
// 保證分子不大于分母,以及分母不為零
while (nums[index - 1] > nums[index] || nums[index] == 0) {
nums[index] = (int) (Math.random()
* (MAX_NUM - MIN_NUM) + MIN_NUM);
}
}
}
final int OP_MAX = 4;
int[] opIndex = new int[OP_MAX]; // 保存操作符下標
// 產生兩個操作符下標。乘以2最多得2
for (int index = 0; index < 2; index++) {
opIndex[index] = (int) (Math.random() * baseNum + 1);
}
char[] op = {' ', '+', '-', '*', '÷'};
// 輸出整個式子,index 表示正在輸出的數字的位置
boolean shouldOutputOp = true;
for (int index = 0; index < 4; index++) {
if (index % 2 == 0) {
System.out.print("(" + nums[index] + "/");
} else if (index % 2 == 1) {
System.out.print(nums[index] + ")");
if (shouldOutputOp) {
System.out.print(op[opIndex[0]]);
shouldOutputOp = false;
} else {
System.out.println("=");
}
}
}
// 求結果
int leftNumerator;
int rightNumerator;
int resultDenominator;
int resultNumerator;
int gcd; // 最大公約數
boolean isDividedByZero = false;
boolean isMultipliedByZero = false;
String simplestNumerator = "";
String simplestDenominator = "";
// 不求最大公倍數,直接乘對方分母
resultDenominator = nums[1] * nums[3];
leftNumerator = nums[0] * nums[3];
rightNumerator = nums[2] * nums[1];
switch (op[opIndex[0]]) {
case '+':
// (等級二)選擇分支一
resultNumerator = leftNumerator + rightNumerator;
gcd = Gcd(resultNumerator, resultDenominator);
simplestNumerator = String.valueOf(resultNumerator / gcd);
simplestDenominator = String.valueOf(resultDenominator / gcd);
break;
case '-':
// (等級二)選擇分支二
resultNumerator = leftNumerator - rightNumerator;
gcd = Gcd(resultNumerator, resultDenominator);
simplestNumerator = String.valueOf(resultNumerator / gcd);
simplestDenominator = String.valueOf(resultDenominator / gcd);
break;
case '*':
// (等級二)選擇分支三
resultNumerator = nums[0] * nums[2];
gcd = Gcd(resultNumerator, resultDenominator);
// 分子有0則結果為0
if (nums[0] == 0 || nums[2] == 0) {
isMultipliedByZero = true;
}
simplestNumerator = String.valueOf(resultNumerator / gcd);
simplestDenominator = String.valueOf(resultDenominator / gcd);
break;
case '/':
// (等級二)選擇分支四
// 除以一個數,等于乘以它的倒數
resultNumerator = nums[0] * nums[3];
resultDenominator = nums[1] * nums[2];
gcd = Gcd(resultNumerator, resultDenominator);
if (nums[0] == 0 || nums[2] == 0) {
isDividedByZero = true;
}
simplestNumerator = String.valueOf(resultNumerator / gcd);
simplestDenominator = String.valueOf(resultDenominator / gcd);
break;
}
if (isDividedByZero) {
standardAnswer[i] = "null"; // 當第二個數的分子為零時無法進行除法運算
} else if (isMultipliedByZero) {
standardAnswer[i] = "0";
} else if (simplestNumerator.equals(simplestDenominator)) {
standardAnswer[i] = "1";
} else if (simplestDenominator.equalsIgnoreCase("1")) {
standardAnswer[i] = simplestNumerator;
} else {
standardAnswer[i] = simplestNumerator + "/" + simplestDenominator;
}
} // 輸出題目并計算答案結束
// 用戶答題
int rightCount = 0;
System.out.println("請輸入你的答案:");
for (int i = 0; i < problemsCount; i++) {
System.out.print((i + 1) + ":");
userAnswer[i] = inputs.next();
if (userAnswer[i].equals(standardAnswer[i])) {
rightCount++;
}
}
System.out.println("標準答案是 : ");
for (int i = 0; i < problemsCount; i++) {
System.out.println((i + 1) + ":" + standardAnswer[i]);
}
DecimalFormat decimal = new DecimalFormat("#.##");
decimal.setRoundingMode(RoundingMode.HALF_UP);
double trueRate = ((double) rightCount / (double) problemsCount) * 100;
System.out.println("True rate:" + decimal.format(trueRate) + "%");
System.out.println("**************************************");
}
當看到 switch (op[opIndex[0]]) {...}
的時候,我的強迫癥犯了,我想先從這里開始。其實應該先簡化它外層的 for 循環,不過這次讓強迫癥贏了……
switch 這部分的完整代碼如下:
int leftNumerator;
int rightNumerator;
int resultDenominator;
int resultNumerator;
int gcd; // 最大公約數
boolean isDividedByZero = false;
boolean isMultipliedByZero = false;
String simplestNumerator = "";
String simplestDenominator = "";
// 不求最大公倍數,直接乘對方分母
resultDenominator = nums[1] * nums[3];
leftNumerator = nums[0] * nums[3];
rightNumerator = nums[2] * nums[1];
switch (op[opIndex[0]]) {
case '+':
// (等級二)選擇分支一
resultNumerator = leftNumerator + rightNumerator;
gcd = Gcd(resultNumerator, resultDenominator);
simplestNumerator = String.valueOf(resultNumerator / gcd);
simplestDenominator = String.valueOf(resultDenominator / gcd);
break;
case '-':
// (等級二)選擇分支二
resultNumerator = leftNumerator - rightNumerator;
gcd = Gcd(resultNumerator, resultDenominator);
simplestNumerator = String.valueOf(resultNumerator / gcd);
simplestDenominator = String.valueOf(resultDenominator / gcd);
break;
case '*':
// (等級二)選擇分支三
resultNumerator = nums[0] * nums[2];
gcd = Gcd(resultNumerator, resultDenominator);
// 分子有0則結果為0
if (nums[0] == 0 || nums[2] == 0) {
isMultipliedByZero = true;
}
simplestNumerator = String.valueOf(resultNumerator / gcd);
simplestDenominator = String.valueOf(resultDenominator / gcd);
break;
case '/':
// (等級二)選擇分支四
// 除以一個數,等于乘以它的倒數
resultNumerator = nums[0] * nums[3];
resultDenominator = nums[1] * nums[2];
gcd = Gcd(resultNumerator, resultDenominator);
if (nums[0] == 0 || nums[2] == 0) {
isDividedByZero = true;
}
simplestNumerator = String.valueOf(resultNumerator / gcd);
simplestDenominator = String.valueOf(resultDenominator / gcd);
break;
}
輸入部分
可以看出,每個分支都會依賴于三個數:resultDenominator 、 leftNumerator 、 rightNumerator 。
我們希望轉發函數的名字為: FracAdd()、FracSub()、FracMulti()、FracDiv()。如果將上面三個數作為參數,轉發函數的命名就會變得奇怪。
Frac 為 Fraction (分數) 的簡寫,這里不簡寫可能會更好
往上面的代碼看,這三個數跟 nums[] 的四個數有關。四個數分別是運算符左邊的分子分母和運算符右邊的分子分母。將這四個數作為參數比較合適。
輸出部分
每個分支都會產生的結果: simplestNumerator 、 simplestDenominator 。這兩個結果組成了一個分數,可以將它們放到一個數組中,然后返回。
不過乘法和除法比較特殊,它們還會分別產生一個布爾變量: isMultipliedByZero 、 isDividedByZero 。可以讓 simplestNumerator 為 0 表示 isMultipliedByZero ; 讓 simplestDenominator 為 0 表示 isDividedByZero 。
老樣子,在分析完輸入輸出之后,創建空方法:
private static int[] FracAdd(int leftNumerator, int leftDenominator, int rightNumerator, int rightDenominator) {
}
private static int[] FracSub(int leftNumerator, int leftDenominator, int rightNumerator, int rightDenominator) {
}
private static int[] FracMulti(int leftNumerator, int leftDenominator, int rightNumerator, int rightDenominator) {
}
private static int[] FracDiv(int leftNumerator, int leftDenominator, int rightNumerator, int rightDenominator) {
}
將 (等級二)選擇分支一
、 (等級二)選擇分支二
、 (等級二)選擇分支三
、 (等級二)選擇分支四
的代碼分別放進去。不過由于之前直接使用 resultDenominator 這些結果,而現在用的參數是 nums[] 來的數,因此要先做處理。
處理之后的代碼如下:
// (等級二)選擇分支一
private static int[] FracAdd(int leftNumerator, int leftDenominator, int rightNumerator, int rightDenominator) {
// 不求最大公倍數,直接乘對方分母
int newLeftNumerator = leftNumerator * rightDenominator;
int newRightNumerator = rightNumerator * leftDenominator;
int resultDenominator = leftDenominator * rightDenominator;
int resultNumerator = newLeftNumerator + newRightNumerator;
int gcd = Gcd(resultNumerator, resultDenominator);
int[] simplestFrac = new int[2];
simplestFrac[0] = resultNumerator / gcd;
simplestFrac[1] = resultDenominator / gcd;
return simplestFrac;
}
// (等級二)選擇分支二
private static int[] FracSub(int leftNumerator, int leftDenominator, int rightNumerator, int rightDenominator) {
// 不求最大公倍數,直接乘對方分母
int newLeftNumerator = leftNumerator * rightDenominator;
int newRightNumerator = rightNumerator * leftDenominator;
int resultDenominator = leftDenominator * rightDenominator;
int resultNumerator = newLeftNumerator - newRightNumerator;
int gcd = Gcd(resultNumerator, resultDenominator);
int[] simplestFrac = new int[2];
simplestFrac[0] = resultNumerator / gcd;
simplestFrac[1] = resultDenominator / gcd;
return simplestFrac;
}
// (等級二)選擇分支三
private static int[] FracMulti(int leftNumerator, int leftDenominator, int rightNumerator, int rightDenominator) {
int[] simplestFrac = new int[2];
// 分子有0則結果為0
if (leftNumerator == 0 || rightNumerator == 0) {
simplestFrac[0] = 0;
} else {
int newLeftNumerator = leftNumerator * rightDenominator;
int newRightNumerator = rightNumerator * leftDenominator;
int resultDenominator = leftDenominator * rightDenominator;
int resultNumerator = newLeftNumerator * newRightNumerator;
int gcd = Gcd(resultNumerator, resultDenominator);
simplestFrac[0] = resultNumerator / gcd;
simplestFrac[1] = resultDenominator / gcd;
}
return simplestFrac;
}
// (等級二)選擇分支四
private static int[] FracDiv(int leftNumerator, int leftDenominator, int rightNumerator, int rightDenominator) {
int[] simplestFrac = new int[2];
if (leftNumerator == 0 || rightNumerator == 0) {
simplestFrac[1] = 0;
} else {
// 除以一個數,等于乘以它的倒數
int resultNumerator = leftNumerator * rightDenominator;
int resultDenominator = leftDenominator * rightNumerator;
int gcd = Gcd(resultNumerator, resultDenominator);
simplestFrac[0] = resultNumerator / gcd;
simplestFrac[1] = resultDenominator / gcd;
}
return simplestFrac;
}
此時的 switch 變成了這樣:
// 求結果
boolean isDividedByZero = false;
boolean isMultipliedByZero = false;
int[] fracResult = new int[2];
switch (op[opIndex[0]]) {
case '+':
break;
case '-':
break;
case '*':
if (fracResult[0] == 0){
isMultipliedByZero = true;
}
break;
case '/':
if (fracResult[1] == 0){
isDividedByZero = true;
}
break;
}
String simplestNumerator = String.valueOf(fracResult[0]);
String simplestDenominator = String.valueOf(fracResult[1]);
將轉發函數填充進去:
// 求結果
boolean isDividedByZero = false;
boolean isMultipliedByZero = false;
int[] fracResult = new int[2];
switch (op[opIndex[0]]) {
case '+':
fracResult = FracAdd(nums[0], nums[1], nums[2], nums[3]);
break;
case '-':
fracResult = FracSub(nums[0], nums[1], nums[2], nums[3]);
break;
case '*':
fracResult = FracMulti(nums[0], nums[1], nums[2], nums[3]);
if (fracResult[0] == 0){
isMultipliedByZero = true;
}
break;
case '/':
fracResult = FracDiv(nums[0], nums[1], nums[2], nums[3]);
if (fracResult[1] == 0){
isDividedByZero = true;
}
break;
}
String simplestNumerator = String.valueOf(fracResult[0]);
String simplestDenominator = String.valueOf(fracResult[1]);
3.3 用戶答題
剛解決掉一個,在統一屏幕又看到了另一個模塊的標題 “用戶答題”。
輸入部分
這個就簡單了,它只需要兩個參數: problemsCount 和 standardAnswer 。甚至連 problemsCount 都可以去掉,只剩下一個。
輸出部分
這個更簡單:無。
老套路,創建空方法:
private static void fracHandleUserAnswer(int problemsCount, String[] standardAnswer) {
}
然后把代碼轉移進去。
...
實在不想再復制了,就把結果略了吧。
3.4 生成標準答案
在 3.2 這一節中,完成了對 switch 的簡化。正如 switch 上面的模塊注釋所說:
// 求結果
switch 連同它下面的 if - else if - else
一起,是為了根據 nums[] 的內容生成答案。
- 輸入部分
數值 nums[] 和運算符 op[opIndex[0]] 。這個運算符可以提前獲取,因此不必將 op[] 和 opIndex[] 都傳進去。 - 輸出部分
String 類型的結果
創建空方法:
private static String fracGetStandardAnswer(int[] nums, char operator) {
}
這次的移入只需將 op[opIndex[0]] 替換成 operator 。
3.5 隨機生成分數
再往上看,最明顯的需要提取的部分就是隨機生成真分數這部分了。
// 第一個真分數。nums[0]為分子,nums[1]為分母
for (int index = 0; index < 2; index++) {
nums[index] = (int) (Math.random()
* (MAX_NUM - MIN_NUM) + MIN_NUM);
if (index == 1) {
// 保證分子不大于分母,以及分母不為零
while (nums[index - 1] > nums[index] || nums[index] == 0) {
nums[index] = (int) (Math.random()
* (MAX_NUM - MIN_NUM) + MIN_NUM);
}
}
}
// 第二個真分數。nums[2]為分子,nums[3]為分母
for (int index = 2; index < 4; index++) {
nums[index] = (int) (Math.random()
* (MAX_NUM - MIN_NUM) + MIN_NUM);
if (index == 3) {
// 保證分子不大于分母,以及分母不為零
while (nums[index - 1] > nums[index] || nums[index] == 0) {
nums[index] = (int) (Math.random()
* (MAX_NUM - MIN_NUM) + MIN_NUM);
}
}
}
生成第一個真分數和生成第二個真分數的代碼幾乎完全一樣,只有 index 不一樣。
這部分的代碼可以簡化,不過還是先盡量保持原樣,等以后再簡化吧。
- 輸入部分
只有 MAX_NUM 和 MIN_NUM 。不過這兩個是我為了消滅 magic number 而創建的,完全可以放到新建的方法里面。 - 輸出部分
第一個部分生成 nums[0] 和 nums[1] ,第二個部分生成 nums[2] 和 nums[3] 。它們共同的特征是:生成兩個數。
這個套路我們是不是見過?在 FracAdd() 那里就是生成兩個數。那么這次我們也這么做。
創建一個空殼函數:
private static int[] getRandomFrac(){
}
轉移代碼:
private static int[] getRandomFrac(){
final int MAX_NUM = 10;
final int MIN_NUM = 1;
int[] nums = new int[2];
for (int index = 0; index < 2; index++) {
nums[index] = (int) (Math.random()
* (MAX_NUM - MIN_NUM) + MIN_NUM);
if (index == 1) {
// 保證分子不大于分母,以及分母不為零
while (nums[index - 1] > nums[index] || nums[index] == 0) {
nums[index] = (int) (Math.random()
* (MAX_NUM - MIN_NUM) + MIN_NUM);
}
}
}
return nums;
}
原來的地方變成:
int[] randomNums;
// 第一個真分數。nums[0]為分子,nums[1]為分母
randomNums = getRandomFrac();
nums[0] = randomNums[0];
nums[1] = randomNums[1];
// 第二個真分數。nums[2]為分子,nums[3]為分母
randomNums = getRandomFrac();
nums[2] = randomNums[0];
nums[3] = randomNums[1];
現在 for 循環已經從 131 行縮減到 40 行了,還能更少嗎?能!
3.6 隨機產生操作符
在原來的代碼中,先隨機生成運算符的下標,當用到運算符的時候再去 op[] 里取出字符。有點兒繞。
final int OP_MAX = 4;
int[] opIndex = new int[OP_MAX]; // 保存操作符下標
// 產生兩個操作符下標。乘以2最多得2
for (int index = 0; index < 2; index++) {
opIndex[index] = (int) (Math.random() * baseNum + 1);
}
char[] op = {' ', '+', '-', '*', '÷'};
...
char operator = op[opIndex[0]];
可以把這部分的代碼抽取出來,直接做成返回運算符的模塊。
- 輸入部分
只有一個: baseNum 。當產生操作符的時候,需要它的值來控制是否能生成乘除運算符。不過它的值是由更上面的代碼決定的,能否延遲決定它的值呢?因為這樣可以讓看代碼的人不必知道 baseNum 的值。 - 輸出部分
字符型的運算符。
先進入支線任務:解決 baseNum 的問題。哪些代碼決定 baseNum 的值呢?
Scanner inputs = new Scanner(System.in);
char useMultiAndDiv = inputs.next().charAt(0);
int baseNum = 0; // 控制操作符是否能為乘號和除號
if (useMultiAndDiv == 'Y' || useMultiAndDiv == 'y') {
baseNum = 4;
} else if (useMultiAndDiv == 'N' || useMultiAndDiv == 'n') {
baseNum = 2;
}
如果延遲 baseNum 的賦值,如何保證其效果仍然按照用戶的輸入來決定?可以用布爾值來代替 baseNum 作為是否使用乘除的狀態。
char choice = inputs.next().charAt(0);
boolean useMultiAndDiv = false;
if (choice == 'Y' || choice == 'y') {
useMultiAndDiv = true;
} else if (choice == 'N' || choice == 'n') {
useMultiAndDiv =false;
}
那么在后面的代碼中,只需判斷 useMultiAndDiv 的值就知道該給 baseNum 賦什么值了。
回到提取代碼的主線任務來,創建空殼新方法:
private static char getRandomOp(boolean useMultiAndDiv){
}
轉移代碼:
private static char getRandomOp(boolean useMultiAndDiv){
int baseNum = useMultiAndDiv ? 4:2;
char[] ops = {' ', '+', '-', '*', '÷'};
int opIndex = (int) (Math.random() * baseNum + 1);
return ops[opIndex];
}
在原來的地方,只需這樣調用:
char operator = getRandomOp(useMultiAndDiv);
麻煩的隨機運算符終于沒了。繼續?
3.7 輸出真分數式子
for 循環里面剩下的比較大塊的代碼就剩下面這部分了:
// 輸出整個式子,index 表示正在輸出的數字的位置
boolean shouldOutputOp = true;
for (int index = 0; index < 4; index++) {
if (index % 2 == 0) {
System.out.print("(" + nums[index] + "/");
} else if (index % 2 == 1) {
System.out.print(nums[index] + ")");
if (shouldOutputOp) {
System.out.print(operator]);
shouldOutputOp = false;
} else {
System.out.println("=");
}
}
}
這部分其實可以簡化得很簡單的,不過還是按照 “盡量不修改原來代碼” 的原則來,把優化放到后面。
- 輸入部分
由于是輸出式子,因此只需兩樣: nums[] 、 operator 。 - 輸出部分
這個部分只是將式子 print 出來,不需要傳出什么結果。
創建空方法:
private static void printFrac(int[] nums,char operator){
}
代碼遷移:
// 輸出整個式子,index 表示正在輸出的數字的位置
private static void printFrac(int[] nums,char operator){
boolean shouldOutputOp = true;
for (int index = 0; index < 4; index++) {
if (index % 2 == 0) {
System.out.print("(" + nums[index] + "/");
} else if (index % 2 == 1) {
System.out.print(nums[index] + ")");
if (shouldOutputOp) {
System.out.print(operator);
shouldOutputOp = false;
} else {
System.out.println("=");
}
}
}
}
原來的地方就剩下一句話:
printFrac(nums,operator);
3.8 真分數模式最后的處理
猜猜 for 循環剩下幾行?
// 輸出題目并計算題目的答案
int[] nums = new int[4];
for (int i = 0; i < problemsCount; i++) {
System.out.print("(" + (i + 1) + ") ");
int[] randomNums;
randomNums = getRandomFrac();
nums[0] = randomNums[0];
nums[1] = randomNums[1];
randomNums = getRandomFrac();
nums[2] = randomNums[0];
nums[3] = randomNums[1];
char operator = getRandomOp(useMultiAndDiv);
printFrac(nums,operator);
standardAnswer[i] = fracGetStandardAnswer(nums, operator);
} // 輸出題目并計算答案結束
只剩下 19 行啦!
趕緊運行一下試試,看能否正常運行。居然沒什么問題!因為一開始就堅持 “盡量不修改原來代碼” 的原則,只要原來的代碼不出現問題,提取之后也不會出問題。
等等!原來的代碼有問題怎么辦?經過一番測試之后……果然有!
來看看原來的分數乘法部分(...三個點表示省略中間代碼):
// 不求最大公倍數,直接乘對方分母
resultDenominator = nums[1] * nums[3];
leftNumerator = nums[0] * nums[3];
rightNumerator = nums[2] * nums[1];
...
// (等級二)選擇分支三
resultNumerator = nums[0] * nums[2];
gcd = Gcd(resultNumerator, resultDenominator);
// 分子有0則結果為0
if (nums[0] == 0 || nums[2] == 0) {
isMultipliedByZero = true;
}
simplestNumerator = String.valueOf(resultNumerator / gcd);
simplestDenominator = String.valueOf(resultDenominator / gcd);
在統一分母時,分子也與分母同乘一個數。兩分母相乘得到新的統一的分母。這時候的狀態是產生了新的表達式,還沒開始乘法。接下去應該是兩個新分子相乘,兩個新分母相乘。
問題來了!上面的代碼中,分母沒有乘,分子相乘時用的是舊的值。
不過神奇的是,在當前版本的代碼中,我們只需往 FracMulti()
里添加:
resultDenominator = resultDenominator * resultDenominator;
這是因為之前往里面填充代碼的時候,看到加減乘除這四個操作基本相同,就從上面的減法里復制代碼過來做少量的修改。
3.9 輪到整數模式了
不知道你發現沒,整數模式和分數模式的用戶輸入處理方式不一樣!整數模式下是出一題回答一題,分數模式下是題目全部出來再回答。為何不統一起來呢?這樣就可以把這兩部分合并起來了。
在 3.3 用戶答題
中,已經將分數的處理封裝起來了。它接收兩個參數: problemsCount 和 standardAnswer[] 。
problemsCount 很容易,在進入 IntegerMode 的時候就有了。現在需要創建 standardAnswer[] 數組,在原來處理輸入的地方換上存儲答案到 standardAnswer 。接著在 for 循環外面使用 handleUserAnswer() 。
其他沒什么說的,比真分數模式的處理簡單很多。修改后的代碼如下:
// (等級一)選擇分支一
private static void IntegerMode(int problemsCount) {
String[] standardAnswer = new String[PROBLEMS_COUNT_MAX];
for (int i = 0; i < problemsCount; i++) {
System.out.print("(" + (i + 1) + ") ");
// 防止出現不好處理的0,很不嚴謹不可取
int[] nums = new int[2];
nums[0] = (int) (Math.random() * 10 + 1);
nums[1] = (int) (Math.random() * 10 + 1);
// 根據隨機的運算符進行相應的操作
int standardResult;
char operator = getRandomOp(true);
switch (operator) {
case '+':
standardResult = addInteger(nums);
break;
case '-':
standardResult = subInteger(nums);
break;
case '×':
standardResult = multiInteger(nums);
break;
case '÷':
standardResult = divInteger(nums);
break;
default:
standardResult = 0;
break;
}
System.out.println(nums[0] + " " + operator + " " + nums[1] + " = ");
standardAnswer[i] = String.valueOf(standardResult);
}
handleUserAnswer(problemsCount,standardAnswer);
}
// (等級二)選擇分支一
private static int addInteger(int[] nums) {
int result = 0;
for (int num : nums) {
result += num;
}
return result;
}
// (等級二)選擇分支二
private static int subInteger(int[] nums) {
if (nums[0] < nums[1]) {
int t = nums[0];
nums[0] = nums[1];
nums[1] = t;
}
return nums[0] - nums[1];
}
// (等級二)選擇分支三
private static int multiInteger(int[] nums) {
int result = 1;
for (int num : nums) {
result *= num;
}
return result;
}
// (等級二)選擇分支四
private static int divInteger(int[] nums) {
if (nums[0] < nums[1]) {
int t = nums[0];
nums[0] = nums[1];
nums[1] = t;
}
// 保證能整除
if (nums[0] % nums[1] != 0) {
nums[0] = (int) (Math.random() * 10 + 1) * nums[1];
}
return nums[0] / nums[1];
}
3.10 接下去是另一個世界
可算是把大部分代碼都模塊化了!真是不容易啊!
要結束了么?
We still have a long way to go.
為什么?盡管進行了一定的模塊化,但所有的代碼仍然在一個 .java
文件里面。并且隨著模塊化的進行,方法越來越多,又雜又亂。
我們似乎可以將這些方法劃分開來,并且放到不同的 .java
(或者說不同的類) 里面。好像有點麻煩,不過所幸之前為此做了準備。
還記得 第 3 步
剛開始說的兩點嗎?
- 方法內不能直接使用全局變量。如果要使用外部的變量,使用參數傳遞;
- 每個方法在處理完一件事之后,使用 return 返回結果。
這為之后的工作提供了便利。
接下去就是另一個世界,你準備好了嗎?
文章列表