抽象類和接口的區別、使用和選擇

不談抽象類能夠有實現等語法糖的問題,本文主要講在語義層面抽象類和接口的本質區別、以及使用以及選擇。ide

 1、介紹

抽象類,首先是個類,類是對現實世界中對象的建模模型,抽象類是對類總體的抽象描述,包含方法,以及屬性。接口是對類某特性行爲的抽象。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定義了飛的行爲:對象

  1. AbstractAirplane是實現了該行爲,而且定義了飛機飛行的模型,PrepareToFly,Step1,Step2。因爲不一樣飛機的Step1和Step2各不相同,因此定義爲Abstract,讓子類本身實現
  2. AbstractBird實現了該行爲,而且定義了鳥的飛行模型,PrepareToFly,Step1,Step2。因爲不一樣鳥的Step1和Step2各不相同,因此定義爲Abstract,讓子類本身實現

上面的例子能夠看出,抽象類一種模版式的設計,接口是一種行爲規範。blog

模版式設計:若是共用部分要修改,好比上圖中的PrepareToFly,則只須要修改共用部分,不須要修改其餘,對於抽象類來講,若是要增長方法,能夠直接操做父類,子類能夠不知情。繼承

行爲規範:若是接口要變動,實現這個接口的類都要修改。接口

2、接口與抽象類的選擇

現實中門有兩個方法Open(), Close(),定義方式分別以下所示:

使用接口方式定義門:

 interface IDoor
    {
        void Open();

        void Close();
    }

 

使用抽象類方式定義門:

 abstract class AbstractDoor
    {
        public abstract void Open();

        public abstract void Close();
    }

 

 

剛開始一切都OK,可是隨着用戶需求的發展,要給門加入報警(Alarm)功能,如今怎麼作?

  1. 把Alarm放入AbstractDoor中,這樣全部繼承自這個類的門都會有Alarm功能,可是並非全部的門都有報警功能,這樣違反了liskov替換原則
  2. 把Alarm放入IDoor接口中,須要Alarm的門都實現這個接口,那麼須要報警的門得同時實現Open和Close功能,其實有些報警的門不必定須要Open和Close功能,

分析:

從上面能夠看出,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()
        {
        }
    }
相關文章
相關標籤/搜索