• C#中抽象類與接口的區別之處

    2016-07-06

        最近在學習設計模式,每個模式都是前人經驗的傳承,是經過總結形成的一套某一類問題的一般性解決方案,說這些其實是有目的的,呵呵不跟大家賣關子了,言歸正傳,我是為了說接口的重要性的,我認為設計模式非常重要,所以其常用的就更重要了,最近學習設計模式的時候總是遇到接口,抽象類,這個模式是抽象類,那個模式是接口,弄的我迷迷糊糊的,決定認真研究一下,下面就跟大家分享一下我研究的結果吧,希望大家多提意見

     

    什么是接口?

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

     

    如何使用接口?

    例如:

    using System; using System.Collections.Generic; using System.Linq; using System.Text;  namespace 用了抽象模式的數據訪問程序 {     class Program     {         static void Main(string[] args)         {             User user = new User();             Department dept = new Department();              //Ifactory factory =new SqlserverFactory();             IFactory factory = new AccessFactory();                          //此時已經與具體的數據庫訪問解除了依賴             IUser iu = factory.CreateUser();              iu.Insert(user);             iu.GetUser(1);              IDepartment id = factory.CreateDepartment();              id.Insert(dept);             id.GetDepartment(1);              Console.Read();          }     }       class User     {         private int id;         public int ID         {             get { return id; }             set { id = value; }         }      }      class Department     {         private int id;         public int ID         {             get { return id; }             set { id = value; }         }               }     //IDepartment接口,用于客戶端訪問,解除與具體數據庫訪問的耦合。     interface IDepartment     {         void Insert(Department department);          Department GetDepartment(int id);     }      //SqlserverDepartment類,用于訪問SQL Server的Department     class SqlserverDepartment : IDepartment     {         public void Insert(Department department)         {             Console.WriteLine("在SQL Server 中給Department表增加一條記錄");         }          public Department GetDepartment(int id)         {             Console.WriteLine("在SQL Server 中根據ID得到Department表一條記錄");             return null;         }          }      //Access類,用于訪問Access的Department     class AccessDepartment : IDepartment     {         public void Insert(Department department)         {             Console.WriteLine("在Access 中給Department表增加一條記錄");         }          public Department GetDepartment(int id)         {             Console.WriteLine("在Access中根據ID得到Department表一條記錄");             return null;         }      }      //IUser接口,用于客戶端訪問,解除與具體數據庫訪問的耦合     interface IUser     {         void Insert(User user);         User GetUser(int id);     }      //SqlserverUser類,用于訪問SQL Server的User     class SqlserverUser : IUser    {         public void Insert(User user)         {             Console.WriteLine("在SQL Server 中給User表增加一條記錄");         }          public User GetUser(int id)         {             Console.WriteLine("在SQL Server中根據ID得到User表一條記錄");             return null;         }      }      //Access類,用于訪問Access的User     class AccessUser : IUser     {         public void Insert(User user)         {             Console.WriteLine("在Access中給User表增加一條記錄");          }         public User GetUser(int id)         {             Console.WriteLine("在Access中根據得到User表一條記錄");             return null;         }     }      //IFactory 接口,定義一個創建訪問Department表對象的抽象的工廠接口      interface IFactory     {         IUser CreateUser();          //增加的接口方法         IDepartment CreateDepartment();     }      //SqlServerFactory類,實現IFactory接口,實例化SqlserverUser和SqlserverDepartment      class SqlserverFactory : IFactory     {         public IUser CreateUser()         {             return new SqlserverUser();          }          public IDepartment CreateDepartment()         {             return new SqlserverDepartment();         }     }      //AccessFactory類,實現IFactory接口,實例化AccessUser和AccessDepartment      class AccessFactory : IFactory     {         public IUser CreateUser()         {             return new AccessUser();          }          public IDepartment CreateDepartment()         {             return new AccessDepartment();         }     } } 


    什么是抽象類?


        抽象類是包含抽象方法的類。那么什么又是抽象方法呢?抽象方法是沒有方法內容的,只有一個方法名和參數列表的方法。并以;結尾。為了標注他的與眾不同,在他的返回類型前加abstract。并在class前加abstract。

    簡言之,由abstract修飾的方法和類就是抽象的方法和類。

     

    如何使用抽象類,抽象方法,和怎樣實現抽象方法?


    例如:

    using System; using System.Collections.Generic; using System.Linq; using System.Text;  namespace 狀態模式結構圖 {     class Program     {         static void Main(string[] args)         {             //設置Context的初始狀態為ConcreteStateA             Context c = new Context(new ConcreteStateA());              //不斷的請求,同時更新狀態             c.Request();             c.Request();             c.Request();             c.Request();              Console.Read();         }     }      //Context類,維護一個COncreteState子類的實例,這個實例定義當前的狀態     class Context     {         private State state;                  //定義Context的初始狀態         public Context(State state)         {             this.state = state;          }          //可讀寫的狀態屬性,用于讀取當前狀態和設置新狀態         public State State         {             get { return state; }             set             {                 state = value;                 Console.WriteLine("當前狀態:" + state.GetType().Name);             }         }          //對請求做處理,并設置下一狀態         public void Request()         {             state.Handle(this);         }      }     //抽象狀態類State,定義一個接口以封裝與Context的一個特定狀態相關的行為     abstract class State     {         public abstract void Handle(Context context);     }      //ConcreteState類,具體狀態,每一個子類實現一個與Context的一個狀態相關的行為     class ConcreteStateA : State     {         public override void Handle(Context context)         {             //設置ConcreteStateA的下一個狀態是ConcreteStateB             context.State = new ConcreteStateB();         }     }      class ConcreteStateB : State     {         public override void Handle(Context context)         {             //設置ConcreteStateB的下一個狀態是ConcreteStateA             context.State = new ConcreteStateA();         }              }  } 


    把接口和抽象類混淆了其實也不能全怪我,因為它們確實有相似之處:

    接口與抽象類的相同點:


          1、不能實例化;

          2、包含未實現的方法聲明;

          3、派生類必須實現未實現的方法,抽象類是抽象方法,接口則是所有成員(不僅是方法包括其他成員);

     

    不過它們還是有很大的區別的


    接口與抽象類的區別:



         1.類是對對象的抽象,可以把抽象類理解為把類當作對象,抽象成的類叫做抽象類.而接口只是一個行為的規范或規定

         2.接口基本上不具備繼承的任何具體特點,它僅僅承諾了能夠調用的方法;     

         3.一個類一次可以實現若干個接口,但是只能擴展一個父類    

         4.接口可以用于支持回調,而繼承并不具備這個特點.     

         5.抽象類不能被密封。   

         6.抽象類實現的具體方法默認為虛的,但實現接口的類中的接口方法卻默認為非虛的,當然您也可以聲明為虛的. 

         7.(接口)與非抽象類類似,抽象類也必須為在該類的基類列表中列出的接口的所有成員提供它自己的實現。但是,允許抽象類將接口方法映射到抽象方法上。   

         8.抽象類實現了oop中的一個原則,把可變的與不可變的分離。抽象類和接口就是定義為不可變的,而把可變的座位子類去實現。   

         9.好的接口定義應該是具有專一功能性的,而不是多功能的,否則造成接口污染。如果一個類只是實現了這個接口的中一個功能,而不得不去實現接口中的其他方法,就叫接口污染。   

        10.盡量避免使用繼承來實現組建功能,而是使用黑箱復用,即對象組合。因為繼承的層次增多,造成最直接的后果就是當你調用這個類群中某一類,就必須把他們全部加載到棧中!后果可想而知.(結合堆棧原理理解)。同時,有心的朋友可以留意到微軟在構建一個類時,很多時候用到了對象組合的方法。比如asp.net中,Page類,有Server Request等屬性,但其實他們都是某個類的對象。使用Page類的這個對象來調用另外的類的方法和屬性,這個是非常基本的一個設計原則。   

        11.如果抽象類實現接口,則可以把接口中方法映射到抽象類中作為抽象方法而不必實現,而在抽象類的子類中實現接口中方法.


    什么時候使用抽象類和接口

     

          1. 如果預計要創建組件的多個版本,則創建抽象類。抽象類提供簡單的方法來控制組件版本。

          2.如果創建的功能將在大范圍的全異對象間使用,則使用接口。如果要設計小而簡練的功能塊,則使用接口。

          3.如果要設計大的功能單元,則使用抽象類.如果要在組件的所有實現間提供通用的已實現功能,則使用抽象類。   

          4.抽象類主要用于關系密切的對象;而接口適合為不相關的類提供通用功能。

     

     

    下面有幾個比喻說的很貼切,大家從中也許也會領悟很多


          1.飛機會飛,鳥會飛,他們都繼承了同一個接口“飛”;但是F22屬于飛機抽象類,鴿子屬于鳥抽象類。

          2.就像鐵門木門都是門(抽象類),你想要個門我給不了(不能實例化),但我可以給你個具體的鐵門或木門(多態);而且只能是門,你不能說它是窗(單繼承);一個門可以有鎖(接口)也可以有門鈴(多實現)。門(抽象類)定義了你是什么,接口(鎖)規定了你能做什么(一個接口最好只能做一件事,你不能要求鎖也能發出聲音(接口污染))。 



    天堂网