繼承"基類"跟繼承"接口"都在大多數情況下都能夠實現某些相同的功能,但它們在具體使用場景也是有區別的.
(一). 接口的優勢
1.接口用於描述一組類的公共方法/公共屬性. 它不實現任何的方法或屬性,只是告訴繼承它的類
《至少》要實現哪些功能, 繼承它的類可以增加自己的方法.
2.使用接口可以使繼承它的類: 命名統一/規范,易於維護.比如: 兩個類 "狗"和"貓",如果它
們都繼承了接口"動物",其中動物裡面有個方法Behavior(),那麼狗和貓必須得實現Behavior()方法,
並且都命名為Behavior這樣就不會出現命名太雜亂的現象.如果命名不是Behavior(),接口會約束
即不按接口約束命名編譯不會通過.
3.提供永遠的接口。當類增加時,現有接口方法能夠滿足繼承類中的大多數方法,沒必要
重新給新類設計一組方法,也節省了代碼,提高了開發效率.
舉個代碼示例:
//公共接口: "動物"
public Interface IAnimal
{
int EyeNumber; //眼睛數量
private void Behavior(); //行為方法,描述各種動物的特性
}
//類: 狗
public Dog : IAnimal
{
string ActiveTime = "白天";
private void Behavior()
{ {
Console.Write("我晚上睡覺,白天活動");
}
}
//類: 貓
public Cat: IAnimal
{
string ActiveTime = "夜晚";
private void Behavior()
{ {
Console.Write("我白天睡覺,晚上活動");
}
}
//簡單的應用:
public static Main()
{
Dog myDog = new Dog();
myDog.Behavior(); //輸出: "我晚上睡覺,白天活動"
Cat myCat = new Cat();
myCat.Behavior(); //輸出: "我白天睡覺,晚上活動"
}
以上調用不同的類的相同名方法,會輸出不同的東東,也就是說每個類裡面的同名方法完成的
功能可以是完全不同的.
更進一步,不是用上面Main方法這樣一個一個調用類的方法,用多態性實現其調用.
看一下下面這個方法:
public Behavior(IAnimal myIanimal)
{
myIanimal.Behavior();
}
其參數是<<接口類型>>,任何繼承它的類都可以調用此方法,此方法能根據類的不同調用不同的類
中的方法. 也即能夠自己根據不同的類,完成不同的類的功能.
多態性代碼示例:
Dog myDog = new Dog();
Cat myCat = new Cat();
Behavior(myDog); //Behavior接受“狗”類實例
Behavior(myCat); //Behavior接受“狗”類實例
這樣Behavior方法寫一次就能完成所有繼承它的類中的相同名方法的不同功能. 非常方便.
同樣,由於“動物軟件”功能需求,需要再增加一個"龜"類:
//類: 龜
public Tortoise: IAnimal
{
string ActiveTime = "很難說";
private void Behavior()
{
Console.Write("我可以不活動,一睡就睡五千年!");
}
}
那麼也可以調用上面多態方法,所以說接口使方法具有較好擴展性.
如果繼承它的類很多的話,有多少好處是可想而知的!
(二). 基類(含抽象類)優勢
1. 在基類中可以加代碼邏輯,但接口不能.
根據上面的Behavior方法的實現:
public Behavior(IAnimal myIanimal)
{
myIanimal.Behavior();
}
重構一下, 如果Dog, Cat等子類不是繼承接口而是繼承基類的話, 可以將 這個方法移到基類中,
真正實現OO的面向對象思想--封裝性, 把類外面方法移到了類內部. 即使用時可以僅使用基類實例的方
法即可完成各個子類的功能, 沒必要讓使用者了解子類(聲明子類的實例). 則代碼會變為:
Dog myDog = new Dog();
Cat myCat = new Cat();
Animal animal = new Animal(Dog);
animal.Behavior();
Animal animal = new Animal(Cat);
animal.Behavior();
2. 如果要在接口中增加一個方法, 所有實現它的類都強制重載一遍此方法, 如果重載類很多時, 會增大工作量.
而繼承類時只要把需要重載(override)的方法, 在基類中指定為虛方法虛方法(virtual)即可.
3. 類繼承較接口可以實現 "代碼重用", 是接口致命弱點, 如Asp.net 2.0中角色成員管理和WebPart的可定制功
能Provider就是一系列抽象基類而不是接口.
(三). 歸納總結
I. 一般在僅實現單繼承用途時, 盡量用基類; 反之使用接口.
II. 如果基類不作為業務對象(在應用時不需要聲明其實例), 則盡量聲明為抽象類; 否則聲明為一般基類.
III. 各個子類如果 公共(重用)代碼較多, 建議使用類繼承方式, 把公共代碼抽象到基類中.
上面是個人對接口某些方面的一些認識,當然接口的作用不只是這些.
不對的地方請讀者批評指正!