不談抽象類能夠有實現等語法糖的問題,本文主要講在語義層面抽象類和接口的本質區別、以及使用以及選擇。ide
抽象類,首先是個類,類是對現實世界中對象的建模模型,抽象類是對類總體的抽象描述,包含方法,以及屬性。接口是對類某特性行爲的抽象。this
對抽象類的繼承纔是Is-A的關係,對接口的實現,則是「有沒有」的關係。好比鳥和飛機都有飛行這個特性,這個時候能夠把飛行這個特性設計爲接口:IFly。而後再讓Airplane和Bird實現IFly這個接口,這樣Airplane和Bird則擁有了飛行這個屬性。spa
接下來飛機可能有多種,鳥也有多種,他們飛行的方法徹底不一樣,這樣就能夠把Airplan和Bird設計成抽象類,讓不一樣的飛機和鳥進行繼承。設計
類圖:code
代碼:orm
public abstract class AbstractAirplane : IFly { public void Fly() { this.PrepareToFly(); this.Step1(); this.Step2(); } private void PrepareToFly() { } protected abstract void Step1(); protected abstract void Step2(); }
public abstract class AbstractBird : IFly { public void Fly() { this.PrepareToFly(); this.Step1(); this.Step2(); } private void PrepareToFly() { } protected abstract void Step1(); protected abstract void Step2(); }
在上面的設計中,IFly定義了飛的行爲:對象
上面的例子能夠看出,抽象類一種模版式的設計,接口是一種行爲規範。blog
模版式設計:若是共用部分要修改,好比上圖中的PrepareToFly,則只須要修改共用部分,不須要修改其餘,對於抽象類來講,若是要增長方法,能夠直接操做父類,子類能夠不知情。繼承
行爲規範:若是接口要變動,實現這個接口的類都要修改。接口
現實中門有兩個方法Open(), Close(),定義方式分別以下所示:
使用接口方式定義門:
interface IDoor { void Open(); void Close(); }
使用抽象類方式定義門:
abstract class AbstractDoor { public abstract void Open(); public abstract void Close(); }
剛開始一切都OK,可是隨着用戶需求的發展,要給門加入報警(Alarm)功能,如今怎麼作?
分析:
從上面能夠看出,Open和Close是一個門的固有屬性,Alarm屬於門的延伸附加行爲,最好的解決辦法是針對Alarm單獨設計一個接口:
public interface IAlarm { void Alarm(); }
普通門的實現:
public class NormalDoor : AbstractDoor { public override void Open() { } public override void Close() { } }
具備報警功能的門的實現:
public class AlarmDoor : AbstractDoor,IAlarm { public override void Open() { } public override void Close() { } public void Alarm() { } }
只能報警的設備的實現:
public class AlarmDevice : IAlarm { public void Alarm() { } }