文章出處

這是一系列模塊化文章的開端。

一切將從一份 JAVA 代碼開始。這份代碼實現了一個能自動生成小學四則運算題目的命令行 “軟件”,滿足以下需求:

  • 除了整數以外,還支持真分數的四則運算。例如:1/6 + 1/8 = 7/24
  • 運算符為 +, −, ×, ÷
  • 能處理用戶的輸入(整數、小數、真分數)
  • 對用戶的輸入判斷對錯,并統計正確率

雖然實現了需求,但是所有的代碼都寫在 main() 方法里面。

這一系列的文章演示了將其一步步模塊化的過程。

初始的代碼如下:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.Scanner;
public class lastdemo {
    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) {
        double count1 = 0;
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        Scanner in1 = new Scanner(System.in);
        System.out.print("請輸入你想要作答的題目數量:");
        int N = in1.nextInt();
        System.out.print("請選擇你要進行的運算:1.整數;2.真分數;");
        /* Scanner in3 = new Scanner(System.in); */
        int input1 = in1.nextInt();
        if (input1 == 1) {
            for (int i = 1; i <= N; i++) {
                int a = (int) (Math.random() * 10 + 1);/* 防止出現不好處理的0,很不嚴謹不可取 */
                int b = (int) (Math.random() * 10 + 1);
                int c = (int) (Math.random() * 4);
                int result = 0;
                switch (c) {
                    case 0:
                        System.out.print("第" + i + "題" + ": ");
                        System.out.print(a + " + " + b + " = ");
                        result = a + b;
                        break;
                    case 1:
                        if (a < b) {
                            int t = a;
                            a = b;
                            b = t;
                        }
                        System.out.print("第" + i + "題" + ": ");
                        System.out.print(a + " - " + b + " = ");
                        result = a - b;
                        break;
                    case 2:
                        System.out.print("第" + i + "題" + ": ");
                        System.out.print(a + " × " + b + " = ");
                        result = a * b;
                        break;
                    case 3:
                        System.out.print("第" + i + "題" + ": ");
                        if (a < b) {
                            int t = a;
                            a = b;
                            b = t;
                        }
                        if (a % b != 0) {
                            a = (int) (Math.random() * 10 + 1) * b;/* 保證能整除 */
                        }
                        System.out.print(a + " ÷ " + b + " = ");
                        result = a / b;
                        break;
                }
                Scanner in2 = new Scanner(System.in);
                int input = in2.nextInt();
                if (input == result) {
                    count1++;
                    System.out.println("答對了,恭喜\n");
                } else {
                    System.out.println("答錯了,加油\n");
                }
            }
            System.out.println("True Rate:" + count1 / N);
        }
        else if (input1 == 2) {
            int max = 100;// 控制算式個數
            char[] op = { ' ', '+', '-', '*', '÷' };// 操作符
            int[] No = new int[4];// 操作符地址
            int useNo = 0;// 控制操作符
            int[] num1 = new int[10];// 操作數
            int[] numberArea = { 1, 10 };// 數值范圍
            String[] Useranser = new String[max];// 用戶輸入的答案
            String[] StandardAnswer = new String[max];// 標準答案
            int f = 0;// 控制輸出真分數的操作符
            int count = 0;// 統計答題正確的數量
            DecimalFormat decimal = new DecimalFormat("#.##");
            decimal.setRoundingMode(RoundingMode.HALF_UP);
            int fz1 = 1;// 分子通分
            int fz2 = 1;// 分子通分
            int fm2 = 1;// 分母通分
            int result = 0;// 分子計算
            int gcd;// 最大公約數
            int fzZeromark = 0;// 分數除法,分子為0標志位
            int fzZeroMark = 0;//
            String zjfz = new String();// 最簡分子
            String zjfm = new String();// 最簡分母
            System.out.print("請選擇是否需要乘除法算術題(Y or N):");// 是否進行乘除法
            char OPP;// 控制是否需要乘除法
            Scanner in2 = new Scanner(System.in);
            OPP = in2.next().charAt(0);
            if (OPP == 'Y' || OPP == 'y') {
                useNo = 4;
            } else if (OPP == 'N' || OPP == 'n') {
                useNo = 2;
            }
            System.out.println("請計算下列真分數計算題。(若無法運算請填入null)");
            System.out.println("***************************************");
            for (int i = 0; i < N; i++) {
                System.out.print("(" + (i + 1) + ") ");
                for (int j = 0; j < 2; j++)// (第一個真分數)
                {
                    num1[j] = (int) (Math.random()
                            * (numberArea[1] - numberArea[0]) + numberArea[0]);// 控制隨機數數值
                    if (j == 1) {
                        while (num1[j - 1] > num1[j] || num1[j] == 0) {
                            num1[j] = (int) (Math.random()
                                    * (numberArea[1] - numberArea[0]) + numberArea[0]);// 控制隨機數數值
                        }
                    }
                }
                for (int j = 2; j < 4; j++)// (第二個真分數)
                {
                    num1[j] = (int) (Math.random()
                            * (numberArea[1] - numberArea[0]) + numberArea[0]);// 控制隨機數數值
                    if (j == 3) {
                        while (num1[j - 1] > num1[j] || num1[j] == 0) {
                            num1[j] = (int) (Math.random()
                                    * (numberArea[1] - numberArea[0]) + numberArea[0]);// 控制隨機數數值
                        }
                    }
                }
                for (int k = 0; k < 2; k++) {// 符號個數
                    No[k] = (int) (Math.random() * useNo + 1);// 隨機產生操作符
                }
                for (int h = 0; h < 4; h++) {// 2個真分數
                    if (h % 2 == 0)
                        System.out.print(("(" + num1[h] + "/"));
                    else if (h % 2 == 1) {
                        System.out.print(num1[h] + ")");
                        if (f < 1) {// 控制只輸出一個操作符
                            System.out.print(op[No[f]]);
                            f++;
                        } else
                            System.out.println("=");
                    }
                }
                f = 0;
                count = 0;
                for (int g = 0; g < 1; g++) {
                    fz1 = num1[0] * num1[3];
                    fz2 = num1[1] * num1[2];
                    fm2 = num1[1] * num1[3];// 分母
                    fzZeromark = 0;
                    fzZeroMark = 0;
                    switch (op[No[g]]) {
                        case '+':
                            result = fz1 + fz2;// 分子
                            gcd = Gcd(result, fm2);// 除以公約數得到最簡分數
                            zjfz = String.valueOf(result / gcd);
                            zjfm = String.valueOf(fm2 / gcd);
                            break;
                        case '-':
                            result = fz1 - fz2;
                            gcd = Gcd(result, fm2);
                            zjfz = String.valueOf(result / gcd);
                            zjfm = String.valueOf(fm2 / gcd);
                            break;
                        case '*':
                            result = num1[0] * num1[2];
                            gcd = Gcd(result, fm2);
                            if (num1[0] == 0 || num1[2] == 0) {
                                fzZeroMark = 1;
                            }
                            zjfz = String.valueOf(result / gcd);
                            zjfm = String.valueOf(fm2 / gcd);
                            break;
                        case '/':// 乘以另一個數的倒數
                            result = num1[0] * num1[3];
                            fm2 = num1[1] * num1[2];
                            gcd = Gcd(result, fm2);
                            if (num1[0] == 0 || num1[2] == 0) {
                                fzZeromark = 1;
                            }
                            zjfz = String.valueOf(result / gcd);
                            zjfm = String.valueOf(fm2 / gcd);
                            break;
                    }
                }
                if (fzZeromark == 1) {
                    StandardAnswer[i] = "null";// 當第二個數的分子為零時無法進行除法運算
                } else if (fzZeroMark == 1) {
                    StandardAnswer[i] = "0";
                } else if (zjfz == zjfm) {
                    StandardAnswer[i] = "1";
                } else if (zjfm.equalsIgnoreCase("1")) {
                    StandardAnswer[i] = zjfz;
                } else {
                    StandardAnswer[i] = zjfz + "/" + zjfm;
                }
            }
            // 答題模板
            System.out.println("請輸入你的答案:");
            for (int i = 0; i < N; i++) {
                System.out.print((i + 1) + ":");
                Scanner in3 = new Scanner(System.in);
                Useranser[i] = in3.next();
                if (Useranser[i].equals(StandardAnswer[i])) {
                    count++;
                }
            }
            System.out.println("標準答案是 :    ");
            for (int i = 0; i < N; i++) {
                System.out.println((i + 1) + ":" + StandardAnswer[i]);
            }
            System.out.println("True rate:"
                    + String.valueOf(decimal
                    .format(((float) count / (float) N) * 100)) + "%");
            System.out.println("**************************************");
        }
        else {
            System.out.println("請輸入1或2:");
        }
        if (null != in) {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

模塊化結束后的版本:點此進入

模塊化前后的文件圖

最終類圖

一些中間步驟的commit

id time commit message tag
26daf92 03-08 16:03 初始版本 (tag: 從網上獲取的最初版本的代碼)
b427867 03-08 20:10 完成變量名的替換 (tag: 完成變量名的替換)
90e4368 03-08 20:29 調整結構并標記模塊
1cd9230 03-08 20:37 第一層模塊化完畢
d29caed 03-08 21:14 分數加減乘除分支轉發函數
7cf2d6b 03-08 21:20 提取出獲取標準答案的部分
65a6155 03-08 21:50 提取出隨機獲取分數的部分
e6541d4 03-08 22:11 提取出分數的輸出和隨機符號
0e75eef 03-08 23:24 提取出整數加減乘除;合并整數和分數對于用戶輸入的處理方式 (tag: 模塊提取基本完成)
a03cae2 03-09 11:35 根據類圖創建類 (tag: 根據類圖創建初始類)
1b67b32 03-09 11:53 整數算式生成放到ExpressionGenerator類里面
7e63cef 03-09 11:54 整數計算放到MyNum里面
508f063 03-09 12:29 完成Expression的實現
eb6ef0d 03-09 14:02 添加對Expression為整數表達式的測試;從測試中發現問題并修復
14c3215 03-09 14:39 簡化LastDemo類的整數部分(程序暫時不能正確運行)
7b61b1c 03-09 15:22 簡化LastDemo類的分數部分
6f8e171 03-09 15:31 實現答案的處理;實現分數表達式的生成
68f585f 03-09 15:44 簡化getExpressionStr()的代碼
bacfb8f 03-09 15:57 抽取讀用戶輸入、輸出答案、輸出正確率
3c0bcb7 03-09 16:38 替換加減乘除符號;生成兩數相減式子時,保證結果為正
31317c0 03-09 17:02 修復部分分數除法答案錯誤的問題;模塊化完成; (tag: 模塊化完成)

文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()