不谈抽象类能够有实现等语法糖的问题,本文主要讲在语义层面抽象类和接口的本质区别、以及使用以及选择。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() { } }