2014年1月30日 星期四

C# - abstract抽象類別的精神


抽象類別是在物件導向設計上面非常熟不可以當飯吃的基礎,不過其實對於初學者而言,是一個很容易混淆的字眼,重點是在於運作的時機點。抽象類別在Java行之有年了,所以對於精於Java開發的人來說,是一個如切豆腐一樣般的細嫩,要切很簡單,但要切的漂亮,可不是人人都做的很好。

對當開發者定義類別時,可以僅宣告方法名稱而不實作當中的邏輯,這樣的方法稱之為「抽象方法」(Abstract method),如果一個類別中包括了抽象方法,則該類別稱之為「抽象類別」(Abstract class),抽象類別是個未定義完全的類別,所以它不能被用來生成物件,它只能被擴充,並於擴充後完成未完成的抽象方法定義。

Java中要宣告抽象方法與抽象類別,您使用"abstract"關鍵字,直接來看個應用的例子,下面定義一個簡單的比大小遊戲抽象類別,以下是Java的例子:

public abstract class AbstractGuessGame {
    private int number;

    public void setNumber(int number) {
        this.number = number;
    }

    public void start() {
        showMessage("Welcome");

        int guess;
        do {
            guess = getUserInput();
            if(guess > number) {
                showMessage("bigger than the goal number");
            }
            else if(guess < number) {
                showMessage("smaller than the goal number");
            }
            else
                showMessage("you win");
        } while(guess != number);
    }

    protected abstract void showMessage(String message);
    protected abstract int getUserInput();
}

abstract 修飾詞表示要修飾的項目遺失或實作不完整。 abstract 修飾詞可用於類別、方法、屬性、索引子 (Indexer) 和事件。 在類別宣告裡使用 abstract 修飾詞,表示該類別只是當做其他類別的基底類別而已。 成員如果標記為抽象,或是包含在抽象類別 (Abstract Class) 內,則必須由衍生自此抽象類別的類別實作這個成員。

C# 中,繼承和介面實作都是由 : 運算子定義,此運算子就等同於 Java 中的 extends implements。基底類別在類別宣告中應該一直位於最左側。
C# Java 一樣,都不支援多重繼承,也就是說類別無法繼承自一個以上類別。不過,可以和在 Java 中一樣,使用介面來達成這個目的。

抽象類別有下列功能:

  • 抽象類別不能執行個體化。
  • 抽象類別可能會包含抽象方法和存取子。
  • 無法使用 sealed (C# 參考) 修飾詞來修改抽象類別,因為這兩個修飾詞意義剛好相反。 sealed 修飾詞可以不讓類別被繼承,而 abstract 修飾詞卻需要類別被繼承。
  • 衍生自抽象類別的非抽象類別必須包含所有繼承抽象方法和存取子的實作。

在方法或屬性宣告裡使用 abstract 修飾詞,表示該此方法或屬性沒有包含實作。
抽象方法有下列特點:

  • 抽象方法隱含是一個虛擬方法。
  • 抽象方法宣告只允許在抽象類別裡。
  • 因為抽象方法宣告沒有提供實際的實作,因此並沒有方法主體,方法宣告僅以分號做為結束而且簽章 (Signature) 之後沒有大括號 ({ })。 例如:
public abstract void MyMethod();
其實作由非抽象類別的成員覆寫方法 override提供。
  • 在抽象方法宣告中使用 static virtual 修飾詞是錯誤的。
所以精簡來說,抽象類別有這些下列特性 :

  • 抽象類別不可以直接使用new令建立物件實體。
  • 抽象類別必須要被繼承才能使用其功能。
  • 抽象類別中,可以宣告抽象方法。
  • 繼承抽象類別的子類別,必須要實作所有抽象方法。
  • 有些功能,在每一個子類別中都一定會被改寫,父類別就不需要維護該方法的實作定義,這種方法就可以宣告為抽象方法。
  • 抽象方法只能宣告在抽象類別中。
  • 宣告抽象方法時不可以使用private修飾詞。
  • 繼承抽象類別的子類別,必須要實作所有的抽象方法。
  • 若是繼承抽象類別的子類別沒有實作所有的抽象方法,則該子類別就必須要宣告為抽象類別。
  • 抽象類別為一定要被繼承的類別,抽象方法為一定要被改寫的方法
  • 宣告不可以再被繼承的類別,使用 sealed修飾詞。
  • 不想再讓繼承的類別改寫其定義,也可以使用sealed 修飾詞。
在這個範例中,Square 類別必須提供 Area 的實作,因為它衍生自 ShapesClass

abstract class ShapesClass
{
    abstract public int Area();
}

class Square : ShapesClass
{
    int side = 0;

    public Square(int n)
    {
        side = n;
    }

    public override int Area()
    {
        return side * side;
    }

    static void Main()
    {
        Square sq = new Square(12);
        Console.WriteLine("Area of the square = {0}", sq.Area());
    }

    interface I
    {
        void M();
    }

    abstract class C:I
    {
        public abstract void M();

    }
}

假設開發者想要實作一個有視窗介面的比大小遊戲,可以擴充並實作抽象方法,事實上,在很多應用場合都可以見到,對於設計模式上的運用,抽象類別是很常見的,開發者可以善加運用。


-雲遊山水為知已逍遙一生而忘齡- 電腦神手


沒有留言:

張貼留言