[C#] 抽象類別與介面

  • 73977
  • 0
  • 2009-12-01

摘要:[C#] 抽象類別與介面

有的時候總會分不清或是忘記這兩個東西的差別,寫下一些心得。

抽象類別:

是用來定義相同種類的物件,所需要具備的共通特性;例如動物(Animal),是所有動物的基底,所有動物具有吃、喝、睡覺等等共同的特性,但是,每種動物吃的東西不一樣(人類屬雜食,老虎只吃肉...),所以我們可以將這些基本特性,寫成抽象類別與方法,讓其他類別來繼承並且實做方法,這就就抽象類別的意義。

介面:

是用來定義不同種類的物件中,針對某種特性,所需要具備的相同功能;我們說,飛機(airplane)會飛,鳥(bird)也會飛,這兩個物件是不同種類的,可是他們都具有會飛的特性,差別在於飛行的方式不同,一個靠機械完成,一個則是拍動翅膀,所以,我們可以將飛行(Fly)寫成介面,物件只要繼承這個介面並且方法,該物件就具有飛行的特性了。

另一種思考:

  • 類別是對物件的抽象:建構物件的各式成員與行為模式。
  • 抽象類別是對類別的抽象:提供基底,專門給同性質的類別繼承。
  • 介面是對行為的抽象:任何類別若繼承介面並且實做後,皆具有此功能。

 

以下是 BBS 找到的解說,大家來參考看看:

Abstract class 主要用來表達有同樣的 property / method / event 的物件
並且這些物件間會有繼承的關係,EX:

                             +--正方形(Square)
               +----四邊形---+--長方形(Rectangle)
               |  (Quadrangle)
形狀(Shape)----+----三角形-------+--等腰三角形(IsoscelesTriangle)
               |  (Triangle)     |--正三角形(RegularTraiangle)
               +----圓形
                  (Circle)

上面所有的有關形狀的 class 都由形狀這個 base abstract class 繼承而來
假設形狀這個 base class 有一個叫「算面積(CalcArea)」的 virtual function
這個「算面積()」的功能在形狀這個 class 裡絕對算不出來(因為沒長寬,也沒半徑)
但是你知道所有的形狀都可以算的出面積
於是你必需在所有繼承形狀的 class 裡實作這個「算面積()」

但是對於程式設計師來說,不管是什麼樣的形狀,只要繼承自形狀
都可以操作「形狀.算面積()」這個 base class 裡的 function 來求出它的面積

範例 code:

Shape a = new Rectangle(width, height);
Shape b = new RegularTriangle(base, height);
double aa = a.CalcArea();
double ba = b.CalcArea();

請注意上面 new 出來的物件是一個 Rectangle,一個 RegularTriagnle
但是都使用 Shape 這個 base class 做操作

再來談 interface,interface 和 abstract class 不同之處
在於它只是一種標記,只要有這種標記的 class,它就「必需」要「能執行」
該 interface 裡所宣告的所有的事項(包括 method, property, event)

也因此 interface 主要用來定立一些共通的操作界面
EX: 汽車喇叭可以按(Push)、販賣機的按鈕也可以按
    但顯然我們不會用同一個 base class 來描述汽車喇叭和販賣機

另外一般來說,interface 給人的感覺會很像簡易版的抽像類別
但它有以下的不同點

1、interface 裡所有被宣告的 property、method、event 都是 public 的
   abstract class 裡你可以有 private 和 protected 的相關宣告


2、interface 裡所有被宣告的 property、method 都必需要被繼承且實作才能使用
   abstract class 你可以不用實作,因為你可以 new 一個 abstract class
   雖然那沒什麼意義,但是你沒辦法直接 new 一個 interface
   你必需 new 出繼承了該 interface 並實作的 class,
   再從那上面取得(Query)該interface

3、interface 在 C# 裡可以多重繼承,class 只能單一繼承

上面看了一定霧殺殺,我用剛剛的 shape 來舉例子
像上面所有繼承自 Shape 的 class 都可以算面積
也因此我可以宣告一個 interface 叫 ICanCalcArea
裡面有一個 CalcArea(),代表含有這個 interface 的 class 都要可以執行
CalcArea() 這件工作

interface ICanCalcArea
{
  double CalcArea();
}

也因此
public class Triangle() : ICanCalcArea { ..... }
public class Rectangle() : ICanCalcArea { ..... }

這代三角形和長方形的 class 都可以含有 ICanCalcArea 這個 interface
也就是說它們都可以算面積,那這樣和 abstract class 有什麼不一樣嗎?

我們再加上一個 class

public class Robot() : ICanCalcArea, IRobotAction { ..... }

一個和形狀扯不上邊的 class -> Robot(機器人) 也可以含有這個 interface
只要它被宣告含有這個 interface,管你是機器人還是火箭,它就是要能夠算面積
並且上面的宣告中,Robot這個 class 還含有另一個 IRobotAction 的 interface
這代表 Robot 這個 class 也必需要能執行 IRobotAction 裡宣告的工作

而 interface 的使用呼叫上也是有所不同的:

// new 出一個 Rectangle 物件 a
Rectangle a = new Rectangle(Width, Height);
// 從 a 上 query 出 ia 這個 ICanCalcArea 的 interface
ICanCalcArea ia = a as ICanCalcArea;
// 使用 query 出的 ICanCalcArea 的 interface 來執行 CalcArea()
if (ia != null)
   double aa = ia.CalcArea();

那 Robot 呢?

Robot b = new Robot(....);
ICanCalcArea ib = b as ICanCalcArea;
if (ib != null)
   double ba = ib.CalcArea();

// 接下來 Query 出 IRobotAction 來執行這個 interface 上的工作
IRobotAction irab = b as IRobotAction;
if (irab != null)
   irab.自爆();  //執行 IRobotAction 裡的 method 自爆

 

Link:

 

三小俠  小弟獻醜,歡迎指教