【公告】網站目前停止所有的課程訂閱服務,原有學員權益不受影響,造成不便還請見諒,我們正在打造更多課程以及圖書,包含 Python 為主的課程主題,未來將會合併且擴充目前的課程內容,提供全新課程訂閱服務,感謝學員的支持。

抽象類別

抽象(abstract)通常表示一種想法、意念,而非真正的實體,當一個類別使用關鍵字 abstract 宣告,表示其為抽象類別,提供其他衍生類別共同的製作樣版。例如建築公司根據房屋樣版模型建造房屋,而各種房屋均擁有出入大門、各式起居房間、衛浴等共同的設施,但是門如何開、房間如何裝潢,則於建造完成進行裝潢時依據屋主需求而定。

抽象類別正是這樣的概念,就如同你無法住在只建好外觀的房屋裏是一樣的,抽象類別本身無法產生實體物件,而且抽象類別包含了一個以上的抽象方法,這些方法只提供函式名稱與參數設定,並且由繼承的衍生類別實作,衍生類別同時必須實作所有抽象類別的方法,否則其本身將成為另一個抽象類別。



左邊的抽象類別A以虛線作表示,由於抽象類別並沒有完整的實作內容,因此無法建立成為物件實體,右邊則是繼承抽象類別的實體類別 B ,其中實作了抽象類別所定義的抽象成員 aMethod 。

類別 B 由於完成了抽象成員 aMethod 的實作,因此本身是一個完整的類別,除了可以建立物件,同時可根據需求,進一步擴充其內容,就如同一般的類別。

抽象類別由 abstract 關鍵字定義,底下為定義抽象類別的語法:

abstract class Absclass

其中的 Absclass 為任意指定的抽象類別名稱,抽象方法同樣必須以 abstract 關鍵字作宣告:

abstract type Absmethod(para-list)

抽象方法本身只有定義,並且由繼承抽象類別的衍生類別進行實作,也就是在衍生類別當中覆寫這些抽象方法成員,就如同覆寫一般類別的虛擬(virtual)成員。

抽象成員由於必須被衍生類別所覆寫,因此它本身即是一個具有 virtual 性質的成員,在衍生類別當中,覆寫這些抽象成員的實作方式與覆寫一般類別的 virtual 成員相同,同樣必須使用以下的敘述:

override type Absmethod(para-list)

以下是一個實際的抽象類別,模擬各種幾何形狀的邊長、面蹟與體積的計算功能,提供作為其他類別所需的基礎架構。

abstract class TemplateClass
{
    public double l = 0;
    public TemplateClass(string shape, double r)
    {
        this.TheShape(shape);
        this.l = r;
    }
    private void TheShape(string shape)
    {
        Console.WriteLine("目前測量的形狀為{0} ", shape);
    }
    public void GetResult()
    {
        Length(l);
        Area(l);
        Volume(l);
    }
    abstract protected void Length(double l);
    abstract protected void Area(double l);
    abstract protected void Volume(double l);
}

public 變數 l 代表所要計算的各種形狀邊長。

建構式接受兩個參數,第一個參數 shape 為形狀種類名稱,第二個參數 r 為邊長,物件建立時,根據所接受的參數,輸出目前所要測量的形狀等訊息,並且將代表邊長的參數值指定給類別層級變數 l 。

public 實體方法 GetResult 執行類別中三個支援周長、面積與體積計算功能的相關方法 - Length、Area 與 Volume ,這三個抽象方法,由衍生類別進行實作。

接下來設計兩個繼承抽象類別的衍生類別,分別是 Square 與 Globe ,這兩個類別均引用 TemplateClass 類別的建構式,然後分別實作圓形與正方形的周長、面積以及體積的計算方法。

class Square : TemplateClass
{
    public Square(string shape, double l):base(shape, l)
    { }
    protected override void Length(double l)
    {
        double squareLength;
        squareLength = 4 * l;
        Console.WriteLine
            ("邊長為{0} 的正方形周長= {1} ", l, squareLength);
    }
    protected override void Area(double l)
    {
        double area;
        area = Math.Pow(l, 2);
        Console.WriteLine
            ("邊長為{0} 的正方形面積= {1} ", l, area);
    }
    protected override void Volume(double l)
    {
        double volume;
        volume = Math.Pow(l, 3);
        Console.WriteLine
            ("邊長為{0} 的立方體體積= {1} ", l, volume);
    }
}

Square 類別繼承 TemplateClass ,實作所有抽象方法成員,並且透過 base 關鍵字引用基礎類別的建構式。

利用 override 關鍵字,覆寫基礎類別的抽象方法 Length ,其中接受一個 double 參數 l ,計算邊長為 l 的正方形周長,並輸出其結果,接下來計算正方形的面積,覆寫抽象方法 Area ,實作正方形面積計算公式,最後實作抽像方法為 Volume 計算正立方體的體積。

class Globe : TemplateClass
{
    public Globe(string shape, double r)
        : base(shape, r)
    { }
    protected override void Length(double r)
    {
        double globeLength;
        globeLength = 4 * Math.PI * r;
        Console.WriteLine
            ("半徑為{0} 的圓形周長= {1} ", r, globeLength);
    }
    protected override void Area(double r)
    {
        double area;
        area = Math.PI * Math.Pow(r, 2);
        Console.WriteLine
            ("半徑為{0} 的圓形面積= {1} ", l, area);
    }
    protected override void Volume(double r)
    {
        double volume;
        volume = (4/3) * Math.PI * Math.Pow(r, 3);
        Console.WriteLine
            ("半徑為{0} 的球體體積= {1} ", l, volume);
    }
}

類別 Globe 同樣引用基礎類別建構式,實作三個不同版本的抽象方法,由於只是調整計算公式的相關敘述,請自行檢視。最後撰寫測試程式。

class Program
{
    static void Main(string[] args)
    {
        const double l = 10;
        Square mySquare = new Square("正方形", l);
        mySquare.GetResult();
        Console.WriteLine();
        Globe myGlobe = new Globe("圓形", l);
        myGlobe.GetResult();
             
        Console.ReadLine();
    }
}

定義一個等於 10 的數值常數 l ,然後以 l 與特定形狀的名稱為參數,分別建立 Square 與 Globe 的實體物件,引用繼承至抽象類別的方法 GetResult,輸出正方形以及圓的周長、面積以及體積計算結果。

目前測量的形狀為 正方形
邊長為 10 的正方形周長 = 40
邊長為 10 的正方形面積 = 100
邊長為 10 的立方體體積 = 1000

目前測量的形狀為 圓形
半徑為 10 的圓形周長 = 125.663706143592
半徑為 10 的圓形面積 = 314.159265358979
半徑為 10 的球體體積 = 3141.59265358979




沒有留言: