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

擴展介面

介面就如同類別,它同樣可以透過繼承而加以擴展,一個介面不必然需要完全重新定義,如果其他介面已經存在相同的定義,透過繼承直接擴充介面型別是不錯的選擇。

介面因為不包含任何實作,因此不會有類別繼承相依的問題發生,C# 不允同時繼承一個以上的基礎類別但是可以同時實作多個不同介面,我們可以透過此種作法來達到多重繼承的目的。

介面繼承與類別的原理相同,一個衍生的介面會同時具備基礎介面所定義的相關成員,介面繼承的語法也完全相同,在稍後的範例當中,你會看到相關的實作。

介面繼承本身並無特殊之處,重點在實作此種介面的行為,由於衍生介面同時繼承了基礎介面的成員,這表示實作此介面的類別,必須同時一併實作繼承關系當中所有的成員。



介面 B繼承了介面 A 因此同時擁有成員 aMethod 以及 bMethod 的定義,而實作介面 B 的類別 C 則必須實作所有三個介面成員,無論它們是由那個介面所定義,而介面的繼承深度即使超過一個以上,上述的規則同樣適用。
來看以下的兩個介面:

interface IMeasure1
{
    void Length();
    void Area();    
}
interface IMeasure2:IMeasure1
{
    void Volume(); 
}

IMeasure2 繼承 IMeasure1 ,因此IMeasure2 包含了 Length 、 Area 以及 Volume 等三個方法成員的定義。接下來定義實作介面 IMeasure2 的類別:

class Square : IMeasure2
{
    public void Length()
    {
        Console.WriteLine("實作Length() 方法");
    }
    public void Area()
    {
        Console.WriteLine("實作Area() 方法");
    }
    public void Volume()
    {
        Console.WriteLine("實作Volume() 方法");
    }
}

Square 類別僅實作 IMeasure2 ,並且實作了 IMeasure2 以及 IMeasure1所有介面成員,接下來測試 Square 類別的效果:

class Program
{
    static void Main(string[] args)
    {
        Square square = new Square();
        square.Length();
        square.Area();
        square.Volume();
        Console.ReadLine();
    }
}

其中建立 Square 物件,然後直接引用並且執行 IMeasure1 與 IMeasure2 介面規格中的方法成員,以下可以看到輸出結果:

實作 Length() 方法
實作 Area() 方法
實作 Volume() 方法

結束前再作個簡單的測試,現在我們將其中 IMeasure1 的方法成員註解掉,如下式:

class Square : IMeasure2
{
    //public void Length()
    //{
    //    Console.WriteLine("實作Length() 方法");
    //}
    //public void Area()
    //{
    //    Console.WriteLine("實作Area() 方法");
    //}
    public void Volume()
    {
        Console.WriteLine("實作Volume() 方法");
    }
}

此時重新編譯執行,你會發現其中出現了未實作 IMeasure1 成員的相關錯誤訊息,這代表繼承 IMeasure2 的類別,必須將IMeasure1與IMeasure2的成員,全部均實作完畢。

實作多重介面

為了避免多重繼承所的複雜度, C# 並不支援多重繼承,所有類別只能繼承單一類別,無論這個類別是抽象還是具體類別,確保單一繼承架構。

多重繼承雖然會增加應用程架構的複雜度,卻有擴充彈性的優點,而我們可以透過實作多個不同的介面間接達到多重繼承的效果。

實作多重介面只需將各介面以逗號隔開即可:

class AClass : Iinterface1,Iinterface2,IinterfaceN
{
 … 
}

其中的 Iinterface1 、 Iinterface2 以及 IinterfaceN ,分別為要實作的介面。

來看一個比較完整的範例,定義兩個不同的介面:

interface IMeasure
{
    void Length(double l);
    void Area(double l);
    double GetVolume(double l);
}
interface IWeight
{
    double GetWeight(double density, double l);
}

IMeasure 定義計算等長幾何形狀長度、寬度以及體積所需的方法規格,介面 IWeight定義一個取得特定形狀物體重量的方法 GetWeight,其中接受兩個參數,一個是代表物體密度的 density ,另一個則是物體邊長 l。

接下來建立類別 Square 一併實作 IMeasure 與 IWeight 介面,並且以逗號隔開:

class Square : IMeasure, IWeight
{
    public void Length(double l)
    {
        double squareLength;
        squareLength = 4 * l;
        Console.WriteLine
            ("邊長為{0} 的正方形周長= {1} ", l, squareLength);
    }
    public void Area(double l)
    {
        double area;
        area = Math.Pow(l, 2);
        Console.WriteLine
            ("邊長為{0} 的正方形面積= {1} ", l, area);
    }
    public double GetVolume(double l)
    {
        double volume;
        volume = Math.Pow(l, 3);
        return volume;
    }
    public double GetWeight(double density, double l)
    {
        double squareVolume = GetVolume(l);
        double Weight = density * squareVolume;
        return Weight;
    }
}

其中的內容同時實作兩個介面的所有方法成員。現在測試 Square 類別:

class Program
{
    static void Main(string[] args)
    {
        double weight;
        Square square = new Square();
        weight = square.GetWeight(2, 5);
        Console.WriteLine("長度為 {0} ,密度為 {1} 的正立方體重量 = {2}", 5, 2, weight);
        Console.ReadLine();
    }
}

建立 Square 類別實體物件 square,引用 GetWeight ,然後輸出計算結果。以下為輸出的訊息

長度為 5 ,密度為 2 的正立方體重量 = 250