再探Java抽象类与接口的设计理念差异

原创 2016年06月01日 15:51:02

Java抽象类与接口都可以实现功能与实现的分离,都对多态提供了很好的支持,那么我们什么时候应该使用抽象类或接口呢?在以前的一篇文章初探Java抽象类与接口中谈到了他们语法的区别,在博客通过模板方法模式深入理解Java抽象类中写到了该如何正确使用抽象类,那么这次我就从更高的层次上——设计思想 上谈谈它们的差异!

1、抽象类与接口的抽象层次是不同的
抽象类是对类抽象,接口是对行为抽象。类包含了属性与行为,所以说接口是更具体的抽象。

2、抽象类与接口的设计层次是不同的
抽象类是一种自下而上的设计,先有子类才能提取公同的属性与行为,抽象出父类;
接口是一种自上而下的设计,先规定行为方法,只要可以实现这些行为,就可以成为接口的实现类。

3、抽象类与其派生类的关系和接口与其实现类的关系本质是不同的
抽象类与其派生类是一种“is-a”关系,即父类和派生子类在概念上的本质是相同的(父子关系,血缘联系,很亲密)。
接口与其实现类是一种“like-a”关系,即接口与实现类的关系只是实现了定义的行为,并无本质上的联系(契约关系,很淡漠的利益关系)。

举个例子:比如说一个动物抽象类,定义了跑的方法、叫的方法,但如果一个汽车类可以实现跑、可以实现叫,它就可以继承动物抽象类吗?!这太不合理了,汽车不是动物呀!而如果通过接口定义跑的方法、叫的方法,汽车类作为实现类实现跑和叫,完全OK很合理,就因为没有继承关系的约束。

为了更好的阐述他们之间的区别,下面将使用一个很棒的例子来说明。该例子引自博文链接

我们有一个Door的抽象概念,它具备两个行为open()和close(),此时我们可以定义通过抽象类和接口来定义这个抽象概念:

抽象类:

abstract class Door{  
    abstract void open();  
    abstract void close();  
}  

接口:

interface Door{  
    void open();  
    void close();  
}  

至于其他的派生类可以通过:
1、使用extends使用抽象类方式定义Door
2、使用implements接口方式定义Door

这里发现两者并没有什么很大的差异,但是现在如果我们需要门具有报警的功能,那么该如何实现呢?

解决方案一:给Door增加一个报警方法:alarm();

abstract class Door{  
    abstract void open();  
    abstract void close();  
    abstract void alarm();  
}  

或者

interface Door{  
    void open();  
    void close();  
    void alarm();  
}  

这种方法违反了面向对象设计中的一个核心原则 ISP (Interface Segregation Principle)—见批注,在Door的定义中把Door概念本身固有的行为方法和另外一个概念”报警器”的行为方法混在了一起。这样引起的一个问题是那些仅仅依赖于Door这个概念的模块会因为”报警器”这个概念的改变而改变,反之依然。

解决方案二
既然open()、close()和alarm()属于两个不同的概念,那么我们依据ISP原则将它们分开定义在两个代表两个不同概念的抽象类里面,定义的方式有三种:
1、两个都使用抽象类来定义。
2、两个都使用接口来定义。
3、一个使用抽象类定义,一个是用接口定义。

由于java不支持多继承所以第一种是不可行的。后面两种都是可行的,但是选择何种就反映了你对问题域本质的理解。

如果选择第二种都是接口来定义,那么就反映了两个问题:
1、我们可能没有理解清楚问题域,AlarmDoor在概念本质上到底是门还报警器。
2、如果我们对问题域的理解没有问题,比如我们在分析时确定了AlarmDoor在本质上概念是一致的,那么我们在设计时就没有正确的反映出我们的设计意图。因为你使用了两个接口来进行定义,他们概念的定义并不能够反映上述含义。

第三种,如果我们对问题域的理解是这样的:AlarmDoor本质上Door,但同时它也拥有报警的行为功能,这个时候我们使用第三种方案恰好可以阐述我们的设计意图。AlarmDoor本质是们,所以对于这个概念我们使用抽象类来定义,同时AlarmDoor具备报警功能,说明它能够完成报警概念中定义的行为功能,所以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(){}  
}  

这种实现方式基本上能够明确的反映出我们对于问题领域的理解,正确的揭示我们的设计意图。其实抽象类表示的是”is-a”关系,接口表示的是”like-a”关系,大家在选择时可以作为一个依据,当然这是建立在对问题领域的理解上的,比如:如果我们认为AlarmDoor在概念本质上是报警器,同时又具有Door的功能,那么上述的定义方式就要反过来了。

批注: ISP(Interface Segregation Principle):面向对象的一个核心原则。它表明使用多个专门的接口比使用单一的总接口要好。
一个类对另外一个类的依赖性应当是建立在最小的接口上的。
一个接口代表一个角色,不应当将不同的角色都交给一个接口。没有关系的接口合并在一起,形成一个臃肿的大接口,这是对角色和接口的污染。

版权声明:本文为博主原创文章,未经博主允许不得转载。

接口的行为抽象和抽象类的行为抽象

选择Java接口还是抽象类 很多人有过这样的疑问:为什么有的地方必须使用接口而不是抽象类,而在另一些地方,又必须使用抽象类而不是接口呢?或者说,在考虑Java类的一般化问题时,很多人会在接口和抽...
  • sanjiaozhen
  • sanjiaozhen
  • 2015年09月26日 03:31
  • 894

Java设计模式概念

设计模式(Design Patterns)                                   ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使...
  • gao_chun
  • gao_chun
  • 2014年06月24日 16:49
  • 4421

大话设计模式JAVA---第二章:接口型模式的相关介绍

接口型模式包含:适配器模式,外观模式,合成模式,桥接模式。 接口的相关感念: 抽象类:进行类型隐藏。比如,三角形和圆形。可以抽象为图形,这样就隐藏了具体的形状。 抽象类和接口的区别:单继承,多实现,度...
  • LQW_java_home
  • LQW_java_home
  • 2016年11月11日 14:21
  • 167

java中抽象类和接口之间的区别和关系

首先抽象类归根结底还是属于类,对于抽象方法,是只能存在于抽象类中的,我们无法再一个非抽象的类中声明一个抽象方法,其次抽象方法只需要声明,并不需要事先。当我们要写一个抽象类的时候只需要在类的前面声明为a...
  • ysayk
  • ysayk
  • 2016年06月12日 23:08
  • 1201

JAVA中接口和抽象类的区别?

原文:http://blog.csdn.net/sunboard/article/details/3831823 1.概述 一个软件设计的好坏,我想很大程度上取决于它的整体架构,而这个整体架构其实...
  • u010355144
  • u010355144
  • 2015年04月08日 18:04
  • 555

Java 抽象类、普通类、接口的区别——值得你一看的干货

【概念】 抽象类、具体类是相对的,并非绝对的。抽象是一种概念性名词,具体是一种可见可触摸的现实对象。概念越小,则其抽象程度就越大,其外延也越大,反之亦然。简单说,比如“人”比“男人”抽象...
  • csdn_aiyang
  • csdn_aiyang
  • 2017年05月04日 16:26
  • 3112

Java中:接口,抽象类,内部类

接口,抽象类,内部类
  • sinat_18268881
  • sinat_18268881
  • 2016年03月09日 16:54
  • 706

java抽象类与接口的区别(谈谈自己的理解)

抽象类?什么是抽象类? 从名字上来讲,我觉得就是对类的一个抽象,把类(事物)抽象出来,当做模板,也就是说在有很多类的时候,我们把一些相似的类的某些方法,某些成员变量抽象出来作为一个模板,让这些类更方...
  • u012883858
  • u012883858
  • 2016年03月14日 11:15
  • 2781

java提高篇(四)-----抽象类与接口

接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法。        抽象类与接口是java语言中对抽象概念进行定义的两种机制,正是由于他们的存在才赋予java强大的面向对象的能力。他们两...
  • chenssy
  • chenssy
  • 2013年10月18日 21:04
  • 142462

JAVA-抽象类和接口的区别总结

首先.抽象类和接口都很好的提供了一种将实现和接口分离的方法..  一、抽象类 我们都知道在面向对象的领域一切都是对象,同时所有的对象都是通过类来描述的,但是并不是所有的类都是来描述对象的。如果一个类没...
  • oshirdey
  • oshirdey
  • 2014年07月26日 15:07
  • 1454
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:再探Java抽象类与接口的设计理念差异
举报原因:
原因补充:

(最多只允许输入30个字)