2017年2月22日 星期三

ATM 02

上次我們建立了一個簡陋的存款功能原型,而非常容易的就能看出,程式充滿了缺陷,不精確的名稱,使用者不需要看到的資訊等等
public class Main {
    // 紀錄存款交易的列表    
    private static List<Integer> save;
    public static void main(String[] args) {
        save = new ArrayList<>();
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入金額:");
        int value = sc.nextInt();
        save.add(value);
        // 為了確認而加上的檢查,並不屬於程式邏輯,應該盡速建立測試取代
        for (int s : save) {
            System.out.println(" "+s);
        }
    }
}

取為Main是代表這裡是整個程式的進入點,這是我的開發習慣,而很明顯的,存款功能並非主流程中應該實現的部分,所以我們決定第一個調整是把存款功能提取成一個函式
deposit();  // called

private static void deposit() {
    Scanner sc = new Scanner(System.in);
    System.out.println("請輸入金額:");
    int value = sc.nextInt();
    save.add(value);
    // 為了確認而加上的檢查,並不屬於程式邏輯,應該盡速建立測試取代
    for (int s : save) {
        System.out.println(" "+s);
    }
}

接著,value是什麼?不明確的名稱帶來誤解和錯誤,我們知道它其實是指存款金額,所以我們把它改成amountOfDeposit
而此處介面和邏輯混雜,只能手動測試結果的狀況顯然是很糟糕的情況,因此我們分離出第一個邏輯"增加存款紀錄"
AddDepositLog(amountOfDeposit);

private static void AddDepositLog(int amountOfDeposit) {
    save.add(amountOfDeposit);
}
接著我們就把最後為了確認而印出save的行為移到測試程式之中
@Test
public void AddDepositLog_should_add_log_into_save() {
    Main.AddDepositLog(1);
    List<Integer> expect = new ArrayList<>();
    expect.add(1);
    Assert.assertEquals(expect, Main.save);
}

在這次的修改之後,我們發現無論是AddDepositLog還是save,都不適合放在Main裡,所以我們必須為它們找到更合適的位置,我們先看save,它是什麼?
    // 紀錄存款交易的列表   
這是註解中清楚說明的事情,所以我第一個動作是創建一個新的類別,它負責管理交易紀錄
public class TransactionLogger {}
接下來我們把save放進去,毫不意外的,語法檢查忠實的報出錯誤
public class TransactionLogger {
    // 紀錄存款交易的列表
    public static List<Integer> save = new ArrayList<>();
}
ps.我不會在這個教學裡面使用重構工具,那當然方便,但你可能因此而對重構不夠了解,甚至換個環境就只能等死,所以我也希望你至少在學習過程中不要使用自動化工具做事,而當你已經能夠了解整個流程,自動化工具才能幫你許多忙,而不是埋下一堆不定時炸彈

原因在於我們忘記了把存取方式改成新的了,所以:
save 改成 TransactionLogger.save
接著執行測試,Oops!出錯了,喔!原來這裡的存取也還沒改
更改之後測試也通過了

save移動成功後,我們想要移動AddDepositLog,一樣移到TransactionLogger
public class TransactionLogger {
    // 紀錄存款交易的列表
    public static List<Integer> save = new ArrayList<>();
    public static void AddDepositLog(int amountOfDeposit) {
        TransactionLogger.save.add(amountOfDeposit);
    }
}
一樣更改各處的存取方式,這時候我們發現一件有趣的事實,原先的MainTest現在完全為了TransactionLogger服務,所以我們改變它的名稱
public class TransactionLoggerTest {
    @Test
    public void AddDepositLog_should_add_log_into_save() {
        TransactionLogger.AddDepositLog(1);
        List<Integer> expect = new ArrayList<>();
        expect.add(1);
        Assert.assertEquals(expect, TransactionLogger.save);
    }
}
這下你可以看到,TransactionLogger已經真正的獨立了

這是程式現在的執行流程

Get Money -> Record transaction


最後,執行測試,通過,這篇就到這裡,下次將開發新的功能,讓我們看看如何將新功能整合進已有的實作之中

NEXT: ATM 03

沒有留言:

張貼留言