预读:
OCP(Open-Closed Principle)--开闭原则指的是一个软件实体应对对扩展开发,对修改关闭(Software entities should be open for extension, but closed for modification)。这个原则是说在设计一个模块的时候,应对使这个模块可以在不被修改的前提下被扩展.
ISP(ISP--Interface Segregation Principle)--使用多个专门的接口比使用单一的总接口要好。一个类对另外一个类的依赖性应当是建立在最小的接口上的。
什么是接口和抽象类?
书面定义:
接口:接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。 接口使用必须遵循ISP(ISP--Interface Segregation Principle)原则。
抽象类:抽象类是跟类与对象之间的关系紧密相关。在面向对象的概念中,我们知道所有的对象都是通过类来描绘的,但是反过来却不是这样。并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。抽象类往往用来表征我们在对问题领域进行分析、设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象。比如:如果我们进行一个图形编辑软件的开发,就会发现问题领域存在着圆、三角形这样一些具体概念,它们是不同的,但是它们又都属于形状这样一个概念,形状这个概念在问题领域是不存在的,它就是一个抽象概念。正是因为抽象的概念在问题领域没有对应的具体概念,所以用以表征抽象概念的抽象类是不能够实例化的。 在面向对象领域,抽象类主要用来进行类型隐藏。我们可以构造出一个固定的一组行为的抽象描述,但是这组行为却能够有任意个可能的具体实现方式。这个抽象描述就是抽象类,而这一组任意个可能的具体实现则表现为所有可能的派生类。模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体,因此它可以是不允许修改的;同时,通过从这个抽象体派生,也可扩展此模块的行为功能。熟悉OCP的读者一定知道,为了能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle)--开闭原则指的是一个软件实体应对对扩展开发,对修改关闭(Software entities should be open for extension, but closed for modification)。这个原则是说在设计一个模块的时候,应对使这个模块可以在不被修改的前提下被扩展.抽象类是其中的关键所在。
--看了一大堆接口与抽象类的区别,头都晕乎乎的,虽然貌似懂了,但是总感觉说不出的别扭。罢了,决定自己给自己总结一下,一切为了更好的使用他们--
个人觉得应该从以下几个方面理解
1、接口与抽象类之间的区别
--首先是继承关系,接口是多继承的关系,接口与接口之间是多继承的,类与接口之间是多实现的关系,而抽象类是一个类,由类对他进行单继承,不能多继承,接口不能继承抽象类,但是抽象类可以实现多接口;接口不能继承类或抽象类,但是抽象类可以继承抽象类和普通类。
--方法以及属性定义方面,抽象类可以定义任何属性的方法以及实现方法,如private、protected、native等等(当然抽象方法有所限制),但是接口定义的方法不能够有实现,且属性必须为public的实例方法,不能有native等定义等等,接口定义的属性必须是public static final的静态常量。--软件开发阶段,接口是属于设计后阶段的定义的,用来协同各个模块以及各个功能之间通信与调用定义的。而抽象类是属于开发前阶段定义的,用来实现功能模块的一些基础的或者公有的或者默认的代码,以及规定一些变动功能与实现所需要依赖的规范。
其实abstract class表示的是"is a"关系,interface表示的是"like a"关系。
2、接口抽象类使用实例
例一:你是一个歌唱家,你老婆是舞蹈家,你们想生一个能歌善舞的人。这个时候,你就只能用接口了。
interface Singer{ void Sing(); } interface Dancer{ void Dance(); } class YourSon implements Singer,Dancer{ void Sing(){}; void Dance(){}; }你不可能用抽象类来实现,编译都过不了,JAVA不允许
abstract class Singer{ void Sing(); } abstract class Dancer{ void Dance(); } class YourSon extends Singer,Dancer{ void Sing(){}; void Dance(){}; }例二: 一扇门Door,该Door具有执行两个动作open和close,此时我们可以通过abstract class或者interface来定义一个表示该抽象概念的类型,定义方式分别如下所示:
abstract class Door { abstract void open(); abstract void close(); }使用interface方式定义Door:
interface Door { void open(); void close(); }其他具体的Door类型可以extends使用abstract class方式定义的Door或者implements使用interface方式定义的Door。看起来好像使用abstract class和interface没有大的区别。
abstract class Door { abstract void open(); abstract void close(); abstract void alarm(); }或者
interface Door { void open(); void close(); void alarm(); }那么具有报警功能的AlarmDoor的定义方式如下:
class AlarmDoor extends Door { void open() { … } void close() { … } void alarm() { … } }或者
class AlarmDoor implements Door {
void open() { … }
void close() { … }
void alarm() { … }
}
这种方法违反了面向对象设计中的一个核心原则ISP(Interface Segregation Priciple),在Door的定义中把Door概念本身固有的行为方法和另外一个概念"报警器"的行为方法混在了一起。这样引起的一个问题是那些仅仅依赖于Door这个概念的模块会因为"报警器"这个概念的改变(比如:修改alarm方法的参数)而改变,反之依然。
推荐解决方案:
共性用抽象类实现,特殊行为规范用接口实现
abstract class Door { abstract void open(); abstract void close(); } interface Alarm { void alarm(); } class AlarmDoor extends Door implements Alarm { void open() { … } void close() { … } void alarm() { … } }总结: 不用太计较到底用接口还是抽象类,给个建议,先用接口,不行了再用抽象类。关键是它能为你服务。