再看抽象類別


撰寫程式常有些看似不合理但又非得完成的需求,舉個例子來說,現在老闆叫你開發一個猜數字遊戲,會隨機產生0到9的數字,使用者輸入的數字與隨機產生的數字相比,如果相同就顯示「猜中了」,如果不同就繼續讓使用者輸入數字,直到猜中為止。

這程式有什麼難的?相信現在的你也可以實作出來:

package cc.openhome;

import java.util.Scanner;

public class Guess {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int number = (int) (Math.random() * 10); 
        int guess;
        do {
            System.out.print("輸入數字:");
            guess = scanner.nextInt();
        } while(guess != number);
        System.out.println("猜中了");
    }
}

圓滿達成任務是吧!當你將程式交給老闆後,老闆皺著眉頭說:「我有說要在文字模式下執行這個遊戲嗎?」你就問了:「請問會在哪個環境下執行呢?」老闆說:「還沒決定,也許會用視窗程式,不過改成網頁也不錯,唔...下個星期開會討論一下。」你問:「那可以下星期討論完我再來寫嗎?」老闆說:「不行!」你(內心OS):「當我是哆啦A夢喔!我又沒有時光機....」

這個例子可笑嗎?在團隊合作、多個部門開發程式時,有許多時候,你不能只是等另一個部門將程式實作出來,也許另一部門要三個月後才能完成程式實作,難道你們這個部門要空轉三個月?有些需求無法決定,卻要撰寫出程式的例子太多了....

有些不合理的需求,本身確實不合理,但有些看似不合理的需求,其實可以設過設計(Design)來解決,以上面的例子來說,取得使用者輸入、顯示結果的環境未定,但你負責的這部份還是可以先實作。例如:

package cc.openhome;

public abstract class GuessGame {
    public void go() {
        int number = (int) (Math.random() * 10); 
        int guess;
        do {
            print("輸入數字:");
            guess = nextInt();
        } while(guess != number);
        println("猜中了");
    }
    
public void println(String text) {
print(text + "\n");
}
public abstract void print(String text); public abstract int nextInt(); }

這個類別的定義不完整,print()nextInt()都是抽象方法,因為老闆還沒決定在哪個環境執行猜數字遊戲,所以如何顯示輸出、取得使用者輸入就不能實作,可以先實作的是猜數字的流程,雖然是抽象方法,但在go()方法中,還是可以呼叫。

等到下星期開會決定,終於還是在文字模式下執行猜數字遊戲,你就再撰寫ConsoleGame類別,繼承抽象類別GuessGame,實作當中的抽象方法即可:

package cc.openhome;

import java.util.Scanner;

public class ConsoleGame extends GuessGame {
    private Scanner scanner = new Scanner(System.in);
    
    @Override
    public void print(String text) {
        System.out.print(text);
    }

    @Override
    public int nextInt() {
        return scanner.nextInt();
    }
}

實際上你只要建構出ConsoleGame實例,執行go()方法過程中呼叫到print()nextInt()方法時,都是執行ConsoelGame中定義的流程,完整的猜數字遊戲就實作出來了。例如:

package cc.openhome;

public class Guess {
    public static void main(String[] args) {
        GuessGame game = new ConsoleGame();
        game.go();
    }
}

一個執行的結果如下:

輸入數字:5
輸入數字:4
輸入數字:3
猜中了