2013年9月10日 星期二

[轉貼] InterFace - 介面、接口

出處:http://jimmy0222.pixnet.net/blog/post/37050866

本文摘自"Introducing Visual C# 2010"(Adam Freeman, Apress, 2010)一書第12章關於介面的內容。
使用介面
介面含有一組用於方法和其它成員的說明。
當一個類別含有在一個介面中定義的所有成員的實現時,稱這個類別實現了一個介面。
在以下章節中,將演示如何定義、實現、及使用介面,並解釋它們與其它C#特性,如抽象類,有何不同。
何時使用介面和基類
基類允許你在派生類中生成共用的行為,當你希望所有類具有同樣的特性並與另一個類相關時,基類是很有用的。你可以在第6章看到相關的示例。
介面允許你跨越無共同先輩的類來生成共同的行為,意即,你可以上溯任何對象,這些對象實現了一個給定介面,並以同樣的代碼處理它們。
定義和使用一個簡單的介面
本節中,我們將考察一個簡單的介面,定義一個實現它的類,並演示如何使用這個類。
定義一個介面
清單12-1含有一個簡單的介面:
?
1
2
3
4
5
public interface IBasicCalculator
{
  int CalculateSum(int x, int y);
  int CalculateProduct(int x, int y);
}
清單12-1中的介面叫做IBasicCalculator。C#中介面命名的約定是遵循Pascal大小寫,並以字母I開頭。你可以在第4章看到一個完整的命名約定列表。
interface1  
圖12-1描述了這個IBasicCalculator介面。
(註:Modifier —修飾符,Keyword —關鍵詞,Name —介面名,Member Specification —成員說明)
介面用Interface關鍵詞進行定義。你可以對介面運用標準的訪問修飾符,修飾符的操作和類的修飾符相同,詳見第6章的說明。介面最重要的部分是成員說明。清單12-1中,指定了兩個方法:CalculateSum和CalculateProduct。這些說明定義了以兩個int整數為參數並返回一個int結果的兩個方法。介面可以包含其它種類的成員,將在本章稍後涉及。
所有介面的成員說明都隱含為public(公用),意即,你不可以用訪問修飾符來限制對它的訪問。
實現一個介面,一旦已經定義了一個介面,你可以生成實現這個介面的類。
清單12-2含有一個類的示例,它實現了清單12-1所定義的介面。
?
1
2
3
4
5
class Calculator : IBasicCalculator
{
  public int CalculateSum(int x, int y) { return x + y; }
  public int CalculateProduct(int x, int y) { return x * y; }
}
實現一個介面就像從一個基類派生一樣。把一個冒號(:)放在類名之後,並加上你想實現的介面名。
你必須在你的類中提供這個介面中的每個 成員的實現。在這個例子中,為了實現這個IBasicClaculator介面,Calculator類必須提供CalculatorSum和 CalculateProduct成員的實現。你的類可以實現附加的成員,但必須至少要實現這個介面中的所有成員。在實現一個介面中所定義的方法時,你不需要用override關鍵詞。
使用一個介面,當一個類已經實現了一個介面時,從這個類生成的對象可以上溯到這個介面類型,如清單12-3所示。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Listing_03 {
  static void Main(string[] args)
  {
    // Create an Object and Upcast it to the interface type
    IBasicCalculator calc = new Calculator();
    // perform some calculations using the interface members
    int sumresult = calc.CalculateSum(100, 100);
    int productresult = calc.CalculateProduct(100, 100);
    // print out the results
    Console.WriteLine("Sum Result: {0}", sumresult);
    Console.WriteLine("Product Result: {0}", productresult);
    // wait for input before exiting
    Console.WriteLine("Press enter to finish");
    Console.ReadLine();
  }
}
在這個例子中,生成了一個新的Calculator對象,並把它賦給一個IBasicCalculator局部變量實現了上溯。一旦把一個對象上溯給一個接口類型,只有該介面中指定的成員才可以被使用。此例中,調用了CalculateSum和CalculateProduct方法,並列印出了結果。
使用介面獲得了基類派生同樣的益處。你的代碼可以在一個給定的抽象層上工作,可以不必修改現存的代碼來定義新類。而且,正如你可能注意到的,我們可以通過使用抽象類獲得與清單1-3代碼同樣的效果(抽象類是在第6章中描述的)。
使用介面的主要優點是可以實現的類不止一個,而這些類不能從一個單一的基類派生(抽象或相反)。事實上,正如我們將從以下小節要看到的,一個類可以有一個基類,並且實現多個介面。
一旦已經定義了一個介面,你可以生成實現這個介面的類。清單12-2含有一個類的示例,它實現了清單12-1所定義的介面。
?
1
2
3
4
5
class Calculator : IBasicCalculator
{
  public int CalculateSum(int x, int y) { return x + y; }
  public int CalculateProduct(int x, int y) { return x * y; }
}
實現一個介面就像從一個基類派生一樣。把一個冒號(:)放在類名之後,並加上你想實現的介面名。
你必須在你的類中提供這個介面中的每個 成員的實現。在這個例子中,為了實現這個IBasicClaculator介面,Calculator類必須提供CalculatorSum和 CalculateProduct成員的實現。你的類可以實現附加的成員,但必須至少要實現這個介面中的所有成員。在實現一個介面中所定義的方法時,你不需要用override關鍵詞。
使用一個介面,當一個類已經實現了一個介面時,從這個類生成的對象可以上溯到這個介面類型,如清單12-3所示。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Listing_03 {
  static void Main(string[] args) {
    // create an object and upcast it to the interface type
    IBasicCalculator calc = new Calculator();
    // perform some calculations using the interface members
    int sumresult = calc.CalculateSum(100, 100);
    int productresult = calc.CalculateProduct(100, 100);
    // print out the results
    Console.WriteLine("Sum Result: {0}", sumresult);
    Console.WriteLine("Product Result: {0}", productresult);
    // wait for input before exiting
    Console.WriteLine("Press enter to finish");
    Console.ReadLine();
  }
}
在這個例子中,生成了一個新的Calculator對象,並把它賦給一個IBasicCalculator局部變量實現了上溯。一旦把一個對象上溯給一個接 口類型,只有該介面中指定的成員才可以被使用。此例中,調用了CalculateSum和CalculateProduct方法,並列印出了結果。
使用介面獲得了基類派生同樣的益處。你的代碼可以在一個給定的抽象層上工作,可以不必修改現存的代碼來定義新類。而且,正如你可能注意到的,我們可以通過使用抽象類獲得與清單1-3代碼同樣的效果(抽象類是在第6章中描述的)。
使用介面的主要優點是可以實現的類不止一個,而這些類不能從一個單一的基類派生(抽象或相反)。事實上,正如我們將從以下小節要看到的,一個類可以有一個基類,並且實現多個介面。
指定介面成員
一個介面可以為將要實現的類指定方法、屬性、事件、和索引子。在本小節中,我將給你示範它們的每一種格式,並演示它們的實現。
指定方法
清單12-1演示了在介面中指定方法。圖12-2描述了第一個方法說明。你可以在第6章瞭解方法的更多內容。
interface2  
當你指定一個方法時,你要提供結果類型(或者如果該方法不返回結果,用void關鍵詞)、你要指定的方法名、以及用於此方法的參數(可選)。
所有介面成員說明都隱含了abstract(抽象)、virtual(虛擬)、和public(公用)。這些關鍵詞在第6章都作瞭解釋。
當一個類實現一個指定了方法的介面時,這個所 實現的方法的返回類型、方法名、以及參數都必須與這個介面所指定的這些對應匹配。該方法的實現必須是public的。你不需要用override關鍵詞來 實現由介面指定的方法。清單12-2演示了一個類實現如圖12-2所指定的方法。
指定屬性
介面可以指定屬性,迫使一個實現該介面的類實現該屬性的訪問器(指屬性的get和set —譯者注)之一或兩個都實現。屬性是在第8章描述的。清單12-4含有指定了一個屬性的介面。
?
1
2
3
4
5
6
public interface IBasicCalculator
{
  int CalculationsPerformedCounter { getset; }
  int CalculateSum(int x, int y);
  int CalculateProduct(int x, int y);
}
介面中的屬性說明以黑體表示,並如圖12-3所示。
interface3  
當你在一個介面中指定一個屬性時,你不要提供該屬性訪問器的實現,也不需要用abstract關鍵詞。正如方法那樣,屬性也是隱含public的,因而也不需要對此屬性使用訪問修飾符關鍵詞。
你可以選擇性地指定訪問器之一,但無論你指定什麼訪問器,它(它們)都必須由實現這個介面的類來實現。以下是實現清單12-4介面的類:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Calculator : IBasicCalculator
{
  private int calcCounter = 0;
  public int CalculationsPerformedCounter
  {
    get return calcCounter; }
    set { calcCounter = value; }
  }
  public int CalculateSum(int x, int y)
  {
    // increment the calculation counter
    CalculationsPerformedCounter++;
    // perofrm the calculation and return the result
    return x + y;
  }
  public int CalculateProduct(int x, int y)
  {
    // increment the calculation counter
    CalculationsPerformedCounter++;
    // perform the calculation and return the result
    return x * y;
  }
}
清單12-4中所指定的屬性的實現如黑體所示。我用一個後台欄位實現了這個屬性,但我也可以用一個自動實現的屬性來代替。為介面實現的屬性必須是public型的。實現一個介面中指定的屬性的類可 以自由地在此屬性的訪問器中添加任意代碼,因此你可以使用第8章中討論的各種技術。
指定一個事件
介面可以指定事件,在一個介面中的一個事件的說明和它在一個類中相應的實現出奇地相似。清單12-5演示了一個指定了事件的介面。你可以在第10章閱讀更多關於事件的內容。
public interface IBasicCalculator { 
  event EventHandler CalculationPerformedEvent; 
  int CalculateSum(int x, int y); 
} 
在這個介面中所指定的事件以黑體顯示,它的描述如圖12-4。
interface4  
與你在一個介面中能夠指定的其它成員一樣,事件是隱含public的,而且在說明中也不用訪問修飾符。以下是實現清單12-5介面的一個類:
?
1
2
3
4
5
6
7
8
9
10
11
class Calculator : IBasicCalculator {
  public event EventHandler CalculationPerformedEvent;
  public int CalculateSum(int x, int y) {
    // calculate the result
    int result = x + y;
    // invoke the event
    CalculationPerformedEvent(this, EventArgs.Empty);
    // return the result
    return result;
  }
}
在這個類中實現的事件與介面中的說明是相同的,附帶了Public訪問修飾符。
指定索引子
剩餘的一種你可以在一個介面中實現的成員是索引子。清單12-6含有一個例子。
?
1
2
3
public interface IBasicCalculator {
  int this[int x, int y] { getset; }
}
清單12-6中的索引子有兩個int參數並返回一個int結果。你可以選擇性地指明一個或兩個訪問器,清單12-6中的說明有兩個。圖12-5描述了索引子說明。

interface5 
與其它成員說明一樣,索引子也是隱含abstract和public的,儘管這兩個關鍵詞你都不需要用。

以下是實現清單12-6介面的一個類:
?
1
2
3
4
5
6
class Calculator : IBasicCalculator {
  public int this[int x, int y] {
    get return x + y; }
    set throw new NotImplementedException(); }
  }
}
這個類使用getter來招待計算,但如果用setter,將彈出一個異常。你可以在第8章閱讀關於索引子的內容,在第14章瞭解異常。
派生介面 Derived Interface
介面可以從其它介面派生而來,與派生類的方式相同。 清單12-7含有一個基介面和一個派生介面。
?
1
2
3
4
5
6
7
interface IBaseCalculator {
  int CalculateSum(int x, int y);
}
 
interface IDerivedCalculator : IBaseCalculator {
  int CalculateProduct(int x, int y);
}
IDerivedCalculator介面派生於IBaseCalculator,你可以通過在介面名後面加一個冒號(:),並指定基介面的方法來派生一個介面。
派生介面繼承基介面的所有成員說明。一個實現IDerivedCalculator的類必須實現該介面所指定的CalculatorProduct方法,以及由基介面所指定的CalculateSum方法。以下是實現這個介面的類:
?
1
2
3
4
class Calculator : IDerivedCalculator {
  public int CalculateProduct(int x, int y) { return x * y; }
  public int CalculateSum(int x, int y) { return x + y; }
}
從實現派生介面的類所生成的對象可以上溯到派生介面和基介面類型,像這樣:
?
1
2
3
4
// create an instance of Calculator and upcast it
IDerivedCalculator derivedCalc = new Calculator();
// upcast the derived interface to the base interface
IBaseCalculator baseCalc = derivedCalc;
當你上溯到基介面時,你只可以訪問由那個介面所指定的成員,就像上溯到基類那樣。

沒有留言:

張貼留言