全面剖析C#介面程式設計之定義介面

哈哈哈哈哈我撒發表於2009-09-29
從技術上講,介面是一組包含了函式型方法的資料結構。通過這組資料結構,客戶程式碼可以呼叫元件物件的功能。
定義介面的一般形式為:

 

[attributes] [modifiers] interface identifier [:base-list] {interface-body}[;]
 
說明:
· attributes(可選):附加的定義性資訊。
· modifiers(可選):允許使用的修飾符有new和四個訪問修飾符。分別是:new、public、protected、internal、 private。在一個介面定義中同一修飾符不允許出現多次,new修飾符只能出現在巢狀介面中,表示覆蓋了繼承而來的同名成員。The public, protected, internal, and private修飾符定義了對介面的訪問許可權。
· 指示器和事件。
· identifier:介面名稱。
· base-list(可選):包含一個或多個顯式基介面的列表,介面間由逗號分隔。
· interface-body:對介面成員的定義。
· 介面可以是名稱空間或類的成員,並且可以包含下列成員的簽名: 方法、屬性、索引器 。
· 一個介面可從一個或多個基介面繼承。
介面這個概念在C#和Java中非常相似。介面的關鍵詞是interface,一個介面可以擴充套件一個或者多個其他介面。按照慣例,介面的名字以大寫字母"I"開頭。下面的程式碼是C#介面的一個例子,它與Java中的介面完全一樣:

 

interface IShape  { 
void Draw ( ) ;
}
如果你從兩個或者兩個以上的介面派生,父介面的名字列表用逗號分隔,如下面的程式碼所示:

 

interface INewInterface: IParent1, IParent2 { }
 
然而,與Java不同,C#中的介面不能包含域(Field)。另外還要注意,在C# 中,介面內的所有方法預設都是公用方法。在Java中,方法定義可以帶有public修飾符(即使這並非必要),但在C#中,顯式為介面的方法指定 public修飾符是非法的。例如,下面的C#介面將產生一個編譯錯誤。

 

interface IShape { public void Draw( ) ; }
 
下面的例子定義了一個名為IControl 的介面,介面中包含一個成員方法Paint:

 

interface IControl {
void Paint( ) ;
}
在下例中,介面 IInterface從兩個基介面 IBase1 和 IBase2 繼承:

 

interface IInterface: IBase1, IBase2 {
void Method1( ) ;
void Method2( ) ;
}
介面可由類實現。實現的介面的識別符號出現在類的基列表中。例如:

 

class Class1: Iface1, Iface2 {
// class 成員。
}
類的基列表同時包含基類和介面時,列表中首先出現的是基類。例如:

 

class ClassA: BaseClass, Iface1, Iface2 {
// class成員。
}
以下的程式碼段定義介面IFace,它只有一個方法:

 

interface IFace {
void ShowMyFace( ) ;
}
不能從這個定義例項化一個物件,但可以從它派生一個類。因此,該類必須實現ShowMyFace抽象方法:

 

class CFace:IFace
{
public void ShowMyFace( ) {
Console.WriteLine(" implementation " ) ;
}
}
基介面
一個介面可以從零或多個介面繼承,那些被稱為這個介面的顯式基介面。當一個介面有比零多的顯式基介面時,那麼在介面的定義中的形式為,介面識別符號後面跟著由一個冒號":"和一個用逗號","分開的基介面識別符號列表。
介面基:
介面型別列表說明:
· 一個介面的顯式基介面必須至少同介面本身一樣可訪問。例如,在一個公共介面的基介面中指定一個私有或內部的介面是錯誤的。
· 一個介面直接或間接地從它自己繼承是錯誤的。
· 介面的基介面都是顯式基介面,並且是它們的基介面。換句話說,基介面的集合完全由顯式基介面和它們的顯式基介面等等組成。在下面的例子中

 

interface IControl {
void Paint( ) ;
}
interface ITextBox: IControl {
void SetText(string text) ;
}
interface IListBox: IControl {
void SetItems(string[] items) ;
}
interface IComboBox: ITextBox, IListBox { }
IComboBox 的基介面是IControl, ITextBox, 和 IlistBox。
· 一個介面繼承它的基介面的所有成員。換句話說,上面的介面IComboBox就像Paint一樣繼承成員SetText 和 SetItems。
· 一個實現了介面的類或結構也隱含地實現了所有介面的基介面。
介面主體
一個介面的介面主體定義介面的成員。

 

interface-body:
{ interface-member-declarationsopt }
介面可以包含一個和多個成員,這些成員可以是方法、屬性、索引指示器和事件,但不能是常量、域、操作符、建構函式或解構函式,而且不能包含任何靜態成員。介面定義建立新的定義空間,並且介面定義直接包含的介面成員定義將新成員引入該定義空間。
說明:
· 介面的成員是從基介面繼承的成員和由介面本身定義的成員。
· 介面定義可以定義零個或多個成員。介面的成員必須是方法、屬性、事件或索引器。介面不能包含常數、欄位、運算子、例項建構函式、解構函式或型別,也不能包含任何種類的靜態成員。
· 定義一個介面,該介面對於每種可能種類的成員都包含一個:方法、屬性、事件和索引器。
· 介面成員預設訪問方式是public。介面成員定義不能包含任何修飾符,比如成員定義前不能加abstract,public,protected,internal,private,virtual,override 或static 修飾符。
· 介面的成員之間不能相互同名。繼承而來的成員不用再定義,但介面可以定義與繼承而來的成員同名的成員,這時我們說介面成員覆蓋了繼承而來的成員,這不會導 致錯誤,但編譯器會給出一個警告。關閉警告提示的方式是在成員定義前加上一個new關鍵字。但如果沒有覆蓋父介面中的成員,使用new關鍵字會導致編譯器 發出警告。
· 方法的名稱必須與同一介面中定義的所有屬性和事件的名稱不同。此外,方法的簽名必須與同一介面中定義的所有其他方法的簽名不同。
· 屬性或事件的名稱必須與同一介面中定義的所有其他成員的名稱不同。
· 一個索引器的簽名必須區別於在同一介面中定義的其他所有索引器的簽名。
· 介面方法宣告中的屬性(attributes), 返回型別(return-type), 識別符號(identifier)和形式引數列表(formal-parameter-lis)與一個類的方法宣告中的那些有相同的意義。一個介面方法宣告 不允許指定一個方法主體,而宣告通常用一個分號結束。
· 介面屬性宣告的訪問符與類屬性宣告的訪問符相對應,除了訪問符主體通常必須用分號。因此,無論屬性是讀寫、只讀或只寫,訪問符都完全確定。
· 介面索引宣告中的屬性(attributes),型別(type)和形式引數列表(formal-parameter-list)與類的索引宣告的那些有相同的意義。
下面例子中介面IMyTest包含了索引指示器、事件E、方法F、屬性P這些成員:

 

interface IMyTest{
string this[int index] { get; set; }
event EventHandler E ;
void F(int value) ;
string P { get; set; }
}
public delegate void EventHandler(object sender, EventArgs e) ;
下面例子中介面IStringList包含每個可能型別成員的介面:一個方法,一個屬性,一個事件和一個索引。

 

public delegate void StringListEvent(IStringList sender);
public interface IStringList
{
void Add(string s);
int Count { get; }
event StringListEvent Changed;
string this[int index] { get; set; }
}
介面成員的全權名
使用介面成員也可採用全權名(fully qualified name)。介面的全權名稱是這樣構成的。介面名加小圓點"." 再跟成員名比如對於下面兩個介面:

 

interface IControl {
void Paint( ) ;
}
interface ITextBox: IControl {
void GetText(string text) ;
}
其中Paint 的全權名是IControl.Paint,GetText的全權名是ITextBox. GetText。當然,全權名中的成員名稱必須是在介面中已經定義過的,比如使用ITextBox.Paint.就是不合理的。
如果介面是名字空間的成員,全權名還必須包含名字空間的名稱。

 

namespace System
{
public interface IDataTable {
object Clone( ) ;
}
}
那麼Clone方法的全權名是System. IDataTable.Clone。
定義好了介面,接下來我們關心的就是怎樣實現對介面的訪問。這部分內容,我將在下一篇文章中和您進一步探討。
 
 
 
什麼是介面?其實,介面簡單理解就是一種約定,使得實現介面的類或結構在形式上保持一 致。個人覺得,使用介面可以使程式更加清晰和條理化,這就是介面的好處,但並不是所有的程式語言都支援介面,C#是支援介面的。注意,雖然在概念上,C# 介面類似於COM介面,但他們的底層結構是不同的。那麼,我們來看一下如何宣告和使用介面。

  宣告介面

  宣告介面在語法上和宣告抽象類完全相同,例如這裡有一個銀行賬戶的介面:
  
public  interface  IBankAccount
{
    
void  PayIn( decimal  amount);
    
bool  Withdraw( decimal  amount);

    
decimal  Balance
    {
        
get ;
    }
}

  注意:介面中只能包含方法、屬性、索引器和事件的宣告。不允許宣告成員上的修飾符,即使是pubilc都不行,因為介面成員總是公有的,也不能宣告為虛擬和靜態的。如果需要修飾符,最好讓實現類來宣告。

  使用介面的例子

  這是書上的一個簡單的例子,但足以說明介面的使用方法。
  一個銀行賬戶的介面,兩個不同銀行賬戶的實現類,都繼承於這個介面。介面宣告如上。下面是兩個賬戶類:

class  SaverAccount : IBankAccount
{
    
private  decimal  balance;

    
public  decimal  Balance
    {
        
get  
        {
            
return  balance;    
        }
    }

    
public  void  PayIn( decimal  amount)
    {
        balance 
+=  amount;
    }

    
public  bool  Withdraw( decimal  amount)
    {
        
if  (balance  >=  amount)
        {
            balance 
-=  amount;
            
return  true ;
        }
        Console.WriteLine(
" Withdraw failed. " );
        
return  false ;
    }

    
public  override  string  ToString()
    {
        
return  String.Format( " Venus Bank Saver:Balance={0,6:C} " , balance);
    }
}

class  GoldAccount : IBankAccount
{
    
private  decimal  balance;

    
public  decimal  Balance
    {
        
get  
        {
            
return  balance;
        }
    }

    
public  void  PayIn( decimal  amount)
    {
        balance 
+=  amount;
    }

    
public  bool  Withdraw( decimal  amount)
    {
        
if  (balance  >=  amount)
        {
            balance 
-=  amount;
            
return  true ;
        }
        Console.WriteLine(
" Withdraw failed. " );
        
return  false ;
    }

    
public  override  string  ToString()
    {
        
return  String.Format( " Jupiter Bank Saver:Balance={0,6:C} " , balance);
    }
}

  可見,這兩個實現類多繼承了IBankAccount介面,因此它們必須要實現介面中的所有宣告的方法。要不然,編譯就會出錯。讓我們來測試一下,下面是測試程式碼:

static  void  Main( string [] args)
{
    IBankAccount venusAccount 
=  new  SaverAccount();
    IBankAccount jupiterAccount 
=  new  CurrentAccount();
    venusAccount.PayIn(
200 );
    jupiterAccount.PayIn(
500 );
    Console.WriteLine(venusAccount.ToString());
    jupiterAccount.PayIn(
400 );
    jupiterAccount.Withdraw(
500 );
    jupiterAccount.Withdraw(
100 );
    Console.WriteLine(jupiterAccount.ToString());

}

  請注意開頭兩句,我們把它們宣告為IBankAccount引用的方式,而 沒有宣告為類的引用,為什麼呢?因為,這樣我們就可以讓它指向執行這個介面的任何類的例項了,比較靈活。但這也有個缺點,如果我們要執行不屬於介面的方 法,比如這裡過載的ToString()方法,就要先把介面的引用強制轉換成合適的型別了。

  介面的繼承

  介面也可以彼此繼承,就象類的繼承一樣。比如我們又宣告一個介面ITransferBankAccount,它繼承於IBankAccount介面。

interface  ITransferBankAccount : IBankAccount 
{
    
bool  TransferTo(IBankAccount destination,  decimal  amount);
}

  在這個介面中,又新增加了一個方法TransferTo(),所以如果我們要寫一個類從ITransferBankAccount繼承的話,就必須要實現IBankAccount和ITransferBankAccount兩個介面所有的方法宣告。即:

class  CurrentAccount : ITransferBankAccount
{
    private  decimal  balance;

    
public  decimal  Balance
    
{
        get
        
{
            return  balance;
        }

    }


    
public  void  PayIn( decimal  amount)
    
{
        balance +=  amount;
    }


    
public  bool  Withdraw( decimal  amount)
    
{
        if  (balance  >=  amount)
        
{
            balance -=  amount;
            
return  true ;
        }

        Console.WriteLine(
" Withdraw failed. " );
        
return  false ;
    }


    
public  override  string  ToString()
    
{
        return  String.Format( " Jupiter Bank Saver:Balance={0,6:C} " , balance);
    }


    
public  bool  TransferTo(IBankAccount destination,  decimal  amount)
    
{
        if  (Withdraw(amount))
        
{
            destination.PayIn(amount);
            return  true ;
        }

        
else
        

            return  false ;
        }

    }

}

  總結起來說,使用C#介面應注意幾個問題:
  1、C#中的介面是獨立於類來定義的。這與 C++模型是對立的,在 C++中介面實際上就是抽象基類。
  2、介面和類都可以繼承多個介面。
  3、類可以繼承一個基類,介面根本不能繼承類。這種模型避免了 C++的多繼承問題,C++中不同基類中的實現可能出現衝突。因此也不再需要諸如虛擬繼承和顯式作用域這類複雜機制。C#的簡化介面模型有助於加快應用程式的開發。
  4、一個介面定義一個只有抽象成員的引用型別。C#中一個介面實際所做的,僅僅只存在著方法標誌,但根本就沒有執行程式碼。這就暗示了不能例項化一個介面,只能例項化一個派生自該介面的物件。
  5、介面可以定義方法、屬性和索引。所以,對比一個類,介面的特殊性是:當定義一個類時,可以派生自多重介面,而你只能可以從僅有的一個類派生。
 

第一節 介面慨述

  介面(interface)用來定義一種程式的協定。實現介面的類或者結構要與介面的定義嚴格一致。有了這個協定,就可以拋開程式設計 語言的限制(理論上)。介面可以從多個基介面繼承,而類或結構可以實現多個介面。介面可以包含方法、屬性、事件和索引器。介面本身不提供它所定義的成員的 實現。介面只指定實現該介面的類或介面必須提供的成員。

  介面好比一種模版,這種模版定義了物件必須實現的方法,其目的就是讓這些方法可以作為介面例項被引用。介面不能被例項化。類可以實現多個介面並且通過這些實現的介面被索引。介面變數只能索引實現該介面的類的例項。例子:

interface IMyExample {
 string this[int index] { get ; set ; }
 event EventHandler Even ;
 void Find(int value) ;
 string Point { get ; set ; }
}
public delegate void EventHandler(object sender, Event e) ;

  上面例子中的介面包含一個索引this、一個事件Even、一個方法Find和一個屬性Point。

  介面可以支援多重繼承。就像在下例中,介面"IComboBox"同時從"ITextBox"和"IListBox"繼承。

interface IControl {
void Paint( ) ;
}
interface ITextBox: IControl {
void SetText(string text) ;
}
interface IListBox: IControl {
void SetItems(string[] items) ;
}
interface IComboBox: ITextBox, IListBox { }

  類和結構可以多重例項化介面。就像在下例中,類"EditBox"繼承了類"Control",同時從"IDataBound"和"IControl"繼承。

interface IDataBound {
 void Bind(Binder b) ;
}
public class EditBox: Control, IControl, IDataBound {
 public void Paint( ) ;
 public void Bind(Binder b) {...}
}

  在上面的程式碼中,"Paint"方法從"IControl"介面而來;"Bind"方法從"IDataBound"介面而來,都以"public"的身份在"EditBox"類中實現。

  說明:

  1、C#中的介面是獨立於類來定義的。這與 C++模型是對立的,在 C++中介面實際上就是抽象基類。

  2、介面和類都可以繼承多個介面。

  3、而類可以繼承一個基類,介面根本不能繼承類。這種模型避免了 C++的多繼承問題,C++中不同基類中的實現可能出現衝突。因此也不再需要諸如虛擬繼承和顯式作用域這類複雜機制。C#的簡化介面模型有助於加快應用程式的開發。

  4、一個介面定義一個只有抽象成員的引用型別。C#中一個介面實際所做的,僅僅只存在著方法標誌,但根本就沒有執行程式碼。這就暗示了不能例項化一個介面,只能例項化一個派生自該介面的物件。

  5、介面可以定義方法、屬性和索引。所以,對比一個類,介面的特殊性是:當定義一個類時,可以派生自多重介面,而你只能可以從僅有的一個類派生。





介面與元件

  介面描述了元件對外提供的服務。在元件和元件之間、元件和客戶之間都通過介面進行互動。因此元件一旦釋出,它只能通過預先定義的接 口來提供合理的、一致的服務。這種介面定義之間的穩定性使客戶應用開發者能夠構造出堅固的應用。一個元件可以實現多個元件介面,而一個特定的元件介面也可 以被多個元件來實現。

  元件介面必須是能夠自我描述的。這意味著元件介面應該不依賴於具體的實現,將實現和介面分離徹底消除了介面的使用者和介面的實現者之間的耦合關係,增強了資訊的封裝程度。同時這也要求元件介面必須使用一種與元件實現無關的語言。目前元件介面的描述標準是IDL語言。

  由於介面是元件之間的協議,因此元件的介面一旦被髮布,元件生產者就應該儘可能地保持介面不變,任何對介面語法或語義上的改變,都有可能造成現有元件與客戶之間的聯絡遭到破壞。

  每個元件都是自主的,有其獨特的功能,只能通過介面與外界通訊。當一個元件需要提供新的服務時,可以通過增加新的介面來實現。不會影響原介面已存在的客戶。而新的客戶可以重新選擇新的介面來獲得服務。

  元件化程式設計

  元件化程式設計方法繼承並發展了物件導向的程式設計方法。它把物件技術應用於系統設計,對物件導向的程式設計的實現過程作了進一步的抽象。我們可以把元件化程式設計方法用作構造系統的體系結構層次的方法,並且可以使用物件導向的方法很方便地實現元件。

  元件化程式設計強調真正的軟體可重用性和高度的互操作性。它側重於元件的產生和裝配,這兩方面一起構成了元件化程式設計的核心。組 件的產生過程不僅僅是應用系統的需求,元件市場本身也推動了元件的發展,促進了軟體廠商的交流與合作。元件的裝配使得軟體產品可以採用類似於搭積木的方法 快速地建立起來,不僅可以縮短軟體產品的開發週期,同時也提高了系統的穩定性和可靠性。

  元件程式設計的方法有以下幾個方面的特點:

  1、程式語言和開發環境的獨立性;

  2、元件位置的透明性;

  3、元件的程式透明性;

  4、可擴充性;

  5、可重用性;

  6、具有強有力的基礎設施;

  7、系統一級的公共服務;

  C#語言由於其許多優點,十分適用於元件程式設計。但這並不是說C#是一門元件程式語言,也不是說C#提供了元件程式設計的工具。我們已經 多次指出,元件應該具有與程式語言無關的特性。請讀者記住這一點:元件模型是一種規範,不管採用何種程式語言設計元件,都必須遵守這一規範。比如組裝計算 機的例子,只要各個廠商為我們提供的配件規格、介面符合統一的標準,這些配件組合起來就能協同工作,元件程式設計也是一樣。我們只是說,利用C#語言進行元件 程式設計將會給我們帶來更大的方便。

  知道了什麼是介面,接下來就是怎樣定義介面,請看下一節--定義介面。

介面的相關陳述
1.一個介面定義了一個契約。
2.介面可以包容方法、C#屬性、事件、以及索引器。
3.在一個介面宣告中,我們可以宣告零個或者多個成員。
4.所有介面成員的預設訪問型別都是public。
5.如果在介面成員宣告中包括了任何修飾符,那麼會產生一個編譯器錯誤。
6.與一個非抽象類類似,一個抽象類必須提供介面中所有成員的實現,只要這些成員在這個類的基類中出現過。
 
介面的理解
1.        面向介面程式設計利用 OO 的一個基本性質 —— 多型,相同方法不同表現。可以這樣想一下, client 編寫自己程式的時候,如果直接面向一個具體類寫程式,那這個程式有個風吹草動的,那 client 就要受到影響,但如果面向一個介面就不同了,某個具體類變了,只知介面,不知具體類的 client 就可以完全不動。 都說上層領導比較好當,因為可以乾的事通常對老百姓來說是虛的,越虛就越不容易錯。
這個道理在 OO 中也是適用的。
2.       換個視角看,面向介面程式設計反映 OO 的另一個方面 —— 封裝,介面將具體實現封裝了起來,可以不影響客戶的情況下切換實現
3.       接 口的作用,一言以蔽之,就是標誌類的類別(type of class)。把不同型別的類歸於不同的介面,可以更好的管理他們。OO的精髓,我以為,是對 物件的抽象,最能體現這一點的就是介面。為什麼我們討論設計模式都只針對具備了抽象能力的語言(比如c++、java、c#等),就是因為設計模式所研究 的,實際上就是如何合理的去抽象。(cowboy的名言是“抽象就是抽去像的部分”,看似調侃,實乃至理)。
 
空介面的使用
在介面使用的時候,空介面有2種情況:
1.類似於ObjectBuilder中的
IBuilderPolicy , 他們往往是做一個標記,表示需要某個功能.當然你也可以這麼用,來表示你的類具有某個功能,實現了你的某個介面.
namespace Microsoft.Practices.ObjectBuilder
{
     ///
     /// Represents a builder policy interface. Since there are no fixed requirements
     /// for policies, it acts as a marker interface from which to derive all other
     /// policy interfaces.
     ///
     public interface IBuilderPolicy
     {
     }
}
 
2. 你的介面繼承了別的介面(非空),你的介面本身沒有宣告函式.這種情況一般是你不希望使用者使用父介面作為引數型別,因為他們的用途可能不同,此時就可以用空介面來實現.
 
interface Text
{
    string getText();
}
 
interface SqlText : Text
{
       
}
可以看到,Text介面是用於返回一個字串.而SqlText是一個 空介面 , 它繼承了Text介面.也就是說SqlText也是一種Text.但是我們可以知道,任何一個字串不一定是Sql字串,所以此時宣告瞭一個SqlText介面來用於表名當前的字串是一個Sql字串.你的函式可以這樣宣告:
public void doQuery(SqlText sqlText)
而不是這樣:
public void doQuery(Text text)
避免使用者產生歧義的想法,一眼看去,就明白應該傳入一個Sql字串.
介面的成員為什麼沒有委託
       我們都知道 C# 的介面是可以包含事件的,其實當我們看到事件的時候,很容易就會想到委託,委託是事件的基礎,如果對委託和事件不是特別清楚的程式設計師就一定不會明白,為什麼 C# 介面中可以包含事件而不能有委託呢。其實簡單的說法就是委託也是型別, delegate 關鍵字引入的是一個新的型別,所以一個 C# 介面無法包容一個委託並把它當作成員;而 event 關鍵字引入的是一個新的成員,因此事件可以歸人介面。理解這點,我們要從 C# 介面的使命說起, C# 接 口是一個契約,規範了介面實現者的行為,而不是要有些什麼。很簡單,例如“黨員”是個介面,它肯定有個動作是“為人民服務”,“某某黨員”實現了“黨員” 這個介面,那麼“某某黨員”肯定也要“為人民服務”,至於你“某某黨員”是否必須擁用“電腦”、“小孩”。那麼“黨員”這個介面中肯定不會有規定。這也就 是介面的目的,規範了實現者的一些行為。所以 C# 介面的成員都是方法,不會有其它了。稍有 c# 常識的程式設計師都明白, c# 中的屬性,其實就是兩個方法,一個 Set 方法,一個 Get 方法,同樣事件和索引器也都是方法,請看下面的介面:
public interface IDrawingObject
    {
        event EventHandler OnDraw;
        string Name
        {
            get ;
            set ;
        }
        int this [int index]
        {
            get ;
            set ;
        }
        void SetValue();
    }
該介面包含了 c# 介面所能接納的所有成員,事件,屬性,索引器,方法。把該介面編譯後,我們用 MSIL Disassembler 工具檢視一下:


這下大家都明白了,其實屬性
Name 對應於 Get_Name(),Set_Name() 這兩個方法,事件 OnDraw 對應於 add_OnDraw(),remove_OnDraw() 這兩個方法,索引器對應於 get_Item(),set_Item() 這兩個方法。在看下面的委託和類的定義:
public delegate void TestEventDelegate (object sender, System.EventArgs e);
class TestClass
    {
        public void SetValue()
        { }
}


看到了吧,定義一個委託和定義一個類是沒有什麼區別的,都是定義了個新的型別。所以
C# 介面是不能有委託的,除非微軟告訴我們 C# 介面中是可以定義類的。

通過學習對C#中介面的作用有了更進一步的理解,拿出來跟大家分享一下,有說的不對的地方請大家指教。
我在上一篇帖子(http://www.programfan.com/club/showbbs.asp?id=150228)中只是簡單的談了一下介面的作用,有興趣的朋友可以去看一下。
言歸正傳:
    假 設我們公司有兩種程式設計師:VB程式設計師,指的是用VB寫程式的程式設計師,用clsVBProgramer這個類表示;Delphi程式設計師指的是用Delphi 寫程式的程式設計師,用clsDelphiProgramer這個類來表示。 每個類都有一個WriteCode()方法。定義如下:

class clsVBProgramer()
{
  ....
  WriteCode()
  {
     //用VB語言寫程式碼;
  }
  ....
}

class clsDelphiProgramer()
{
  ....
  WriteCode()
  {
    //用Delphi語言寫程式碼;
  }
   ....
}

現在公司來了一個專案,要求派某個程式設計師寫一個程式。
class clsProject()
{
  ....
  WritePrograme(clsVBProgramer programer)//用VB寫程式碼
  {
    programer.WriteCode();
  }
  WritePrograme(clsDelphiProgramer programer)//過載方法,用Delphi寫程式碼
  {
    programer.WriteCode();
  }
 ......
}
在主程式中我們可以這樣寫:
main()
{
   clsProject proj=new  clsProject;
   //如果需要用VB寫程式碼
   clsVBProgramer programer1=new clsVBProgramer;
   proj.WritePrograme(programer1);
   //如果需要用Delphi寫程式碼
   clsDelphiProgramer programer2=new clsDelphiProgramer;
   proj.WritePrograme(programer2);
}

但 是如果這時公司又來了一個C#程式設計師,我們怎麼改這段程式,使它能夠實現用C#寫程式的功能呢?我們需要增加一個新類 clsCSharpProgramer,同時在此clsProject這個類中要再次過載 WritePrograme(clsCSharpProgramer programer)方法。這下麻煩多了。如果還有C程式設計師,C++程式 員,JAVA程式設計師呢。麻煩大了!

但是如果改用介面,就完全不一樣了:
首先宣告一個程式設計師介面:
interface IProgramer()
{
  WriteCode();
}
然後宣告兩個類,並實現IProgramer介面:
class clsVBProgramer():IProgramer
{
  ....
  WriteCode()
  {
     //用VB語言寫程式碼;
  }
  ....
}

class clsDelphiProgramer():IProgramer
{
  ....
  WriteCode()
  {
    //用Delphi語言寫程式碼;
  }
   ....
}
對clsProject這個類進行一下修改:
class clsProject()
{
  ....
  WritePrograme(IProgramer programer)
  {
    programer.WriteCode();//寫程式碼
  }
  ......
}

main()
{
   clsProject proj=new  clsProject;
   IProgramer programer;
   //如果需要用VB寫程式碼
   programer=new clsVBProgramer;
   proj.WritePrograme(programer);
   //如果需要用Delphi寫程式碼
   programer=new clsDelphiProgramer;
   proj.WritePrograme(programer);    
}
如果再有C#,C,C++,JAVA這樣的程式設計師新增進來的話,我們只需把它們相關的類加進來,然後在main()中稍做修改就OK了。擴充性特別好!

另外我們如果把clsProject這個類封成一個元件,那麼當我們的使用者需要要擴充功能的時候,我們只需要在外部做很小的修改就能實現,可以說根本就用不著改動我們已經封好元件!是不是很方便,很強大!

C#中的介面和Java中的介面差不多,但是有更大的彈性。類可以隨意地顯式實現某個介面:

public interface ITeller

{

void Next ();

}

public interface IIterator

{

void Next ();

}

public class Clark : ITeller, IIterator

{

void ITeller.Next () {}

void IIterator.Next () {}

}


這給實現介面的類帶來了兩個好處。其一,一個類可以實現若干介面而不必擔心命名衝突問題。其二,如果某方法對一般使用者來說沒有用的話,類能夠隱藏該方法。顯式實現的方法的呼叫,需把類【譯註:應該是物件】造型轉換為介面:

Clark clark = new Clark();

((ITeller)clark).Next();

相關文章