|
|
在Java當中,你還可以定義抽象類別(Abstract Class)。表面上看來,定義類別時僅宣告方法名稱而不實作當中的邏輯,因為該方法定義不完整,這樣的方法稱之為抽象方法(Abstract Method),如果一個類別中包括了抽象方法,因為該類別定義不完整,所以該類別稱之為抽象類別。在 繼承了什麼? 中看過一個基本的例子。 然而事實上,不管類別是否標示為abstract,定義類別,本身就是在進行抽象化,到底什麼稱之為抽象?「象」這個字眼最直接的描述,就是代表著「事物的輪廓」,你看到一隻麻雀、一隻鴿子、一隻雞,你會知道它們都是鳥,因為從它們形態的輪廓上,你可以歸納(抽)出一些共同的表象(象)。有些共同表象看得到具體的行為,但有些不是。 所以如何使用抽象類別,其中一個方式就是在如何為你所定義的類別歸納出一些共同的表象,並發掘出其中無法看出具體行為的部份。單純地以一隻麻雀、一隻鴿子、一隻雞,假設你所看到的共同表象是一對翅膀、一對腳、會振翅,因而抽取出來定義為鳥類所應共同具有的特性: public abstract class Bird { private int leg; private int wing; public abstract void flutter(); } 這是抽象類別的基本使用方式之一。 「象」這個字眼也可以進一步描述為「流程的輸廓」,不僅僅是「表象」,也就是這個事物在進行某個行為時,整個流程的大致順序。舉個例子來說,猜數字遊戲的流程大致就是: 顯示訊息(歡迎) 隨機產生數字 遊戲迴圈 顯示訊息(提示使用者輸入) 取得使用者輸入 比較是否猜中 顯示訊息(輸入正確與否) 在描述流程輸廓時,並沒有提及如何顯示訊息、沒有提及如何取得使用者輸入等具體的作法,只是歸納出一些共同的流程步驟。 public abstract class GuessGame { protected String welcome; protected String prompt; protected String correct; protected String bigger; protected String smaller; public void go() { message(welcome); int number = (int) (Math.random() * 10); int guess = 0; do { message(prompt); guess = guess(); if(guess > number) { message(bigger); } else if(guess < number) { message(smaller); } } while(guess != number); message(correct); } protected abstract void message(String message); protected abstract int guess(); } 如果是個文字模式下的猜數字遊戲,可以將顯示訊息、取得使用者輸入等以文字模式下的具體作法實現出來。例如: import java.util.Scanner; public class ConsoleGame extends GuessGame { private Scanner scanner; public ConsoleGame() { welcome = "歡迎"; prompt = "輸入"; correct = "猜中了"; bigger = "你猜的比較大"; smaller = "你猜的比較小"; scanner = new Scanner(System.in); } protected void message(String msg) { System.out.println(msg); } protected int guess() { return scanner.nextInt(); } } 你可以這麼使用: GuessGame game = new ConsoleGame(); game.go(); 抽象還可以再更進一步,不僅是流程的抽象,還可以是所使用物件的抽象。舉個例子來說,你正在設計一個文字編輯器的框架,實際上文字編輯器會開啟的格式並不知道,但基本文件處理的幾個抽象流程打算事先定義下來: public abstract class Editor { private Document document; public abstract Document createDocument(); public void newDoc() { document = createDocument(); document.show(); } public void saveDoc() { if(document != null) document.save(); } public void closeDoc() { if(document != null) document.close(); } } public interface Document { void show(); void save(); void close(); } 這樣的作法,是將產生實際Document的責任推遲至子類別來實現,你僅抽象地定義父類別的流程與Document的行為(後者利用到介面來定義就是了)。也許你會設計一個XML編輯器,在實現createDocument()方具體指定所產生的Document物件: public class XMLEditor extends Editor { public Document createDocument() { return new Document() { public void show() { /* XML 文件顯示.... */ } public void save() { /* XML 文件儲存.... */ } public void close() { /* XML 文件關閉.... */ } }; } } 抽象所代表的是抽取出「事物的輪廓」,你如何決定輪廓就決定了你如何定義抽象,或者更具體而言,如何使用抽象類別。 |