- 抽象类的理解
- 接口的理解
- 区别分析
- 演示案例
- 总结
- 参考
动物就是对某类事物的普遍性、共同性进行抽取后得到的用来反映这类事物本质的概念。 动物被定义为靠摄取有机物(植物、动物或微生物)来获得营养而不能完成无机物到有机物转化过程的能够对环境作出反应并移动的生物。
动物其实是对一大类事物进行抽象得到的概念,这种概念还是比较笼统的,那么在 Java 语言中,则将动物这种事物抽象成一个抽象类(即声明定义一个抽象类来描述动物这种事物)
猫是对某类具体的事物进行抽象得到的具体概念,那么在 Java 语言中,则将猫这种事物抽象成一个具体类(即声明定义一个具体类来描述猫这类具体的事物)
接口的理解行为是对各种事物表现出来的外表活动进行抽象得到的概念,这种概念同样是笼统的。就算是更具体的概念“飞行”,其实对于不同种的事物而言,“飞行”的具体内容也是有很大区别的。例如,人类的飞行是通过滑翔伞,或者喷气式飞行设备;鸟的飞行则是通过自身的翅膀。所以在 Java 语言中,适合将某类事物的各种行为/动作抽象成一个接口(声明定义一个接口(纯抽象类)来描述各种事物的行为/动作)。
在软件中接口是一种规范(标准/约定/协议),接口可以约束类的行为,接口是一些方法特征的集合,但是没有方法的实现,接口其实上也可以看做是一个特殊的抽象类,但是两者的设计理念完全不同,抽象类有利于代码复用,接口利于代码的扩展和维护。
接口通过抽象方法来描述一组行为规范
接口(interface)不是一个类,它是抽象方法的集合。一个类实现一个接口,从而继承和实现接口的抽象方法。
区别分析抽象类是对一种事物的抽象,而接口是对行为的抽象。抽象类是对某种事物整体进行抽象,包括属性、行为,但是接口只是对事物的某些行为进行抽象。
类描述对象的属性和行为。接口仅仅约定了事物的行为。
举个简单的例子,飞机和鸟是不同类的事物,但是它们都有一个共性,就是都会飞。那么在设计的时候,可以将飞机设计为一个类 Airplane,将鸟设计为一个抽象类 Bird,但是不能将“飞行”这个特性也设计为类,因此它只是一个行为特性,并不是对一类事物的抽象描述。此时可以将“飞行”设计为一个接口 Fly,包含方法 fly(),然后 Airplane 和 Bird 分别根据自己的需要实现 Fly 这个接口。至于有不同种类的飞机,比如战斗机、民用飞机等直接继承 Airplane 即可,对于鸟也是类似的,不同种类的鸟直接继承 Bird 类即可。从这里可以看出,继承是一个 "是不是"的关系,而接口实现则是 "有没有"的关系。继承解决"是不是"的问题,接口解决“有没有”的问题。
比如某种生物如果属于鸟类,那么就是继承 bird,这种生物是否有“飞行”这种特点呢?能飞行则可以实现这个接口 Fly,不能飞行就不实现这个接口。
演示案例门和警报的例子:门都有 open() 和 close() 两个动作,此时我们可以通过抽象类或者接口来声明(描述)这两个抽象概念。
抽象类:
abstract class Door {
public abstract void open();
public abstract void close();
}
接口:
interface Door {
public abstract void open();
public abstract void close();
}
现在有个需求,有些门具有报警功能,那么该如何实现这样的需求呢?
将 open() 、close() 和 alarm() 都声明在一个接口中,行不行? 我们分析下: 有些门具有报警功能,那么去实现这个接口就可以了;而有些门不具有报警功能,但是具有基本的 open()、close() 功能,难道也去实现这个接口吗?如果去实现这个接口,那么就必须实现 alarm(),这并不符合需求呀。如果将来需要做个火灾报警器,这个报警器具有 alarm() 功能,但是不具有 open()、close() 功能,火灾报警器为了实现报警的功能去实现这个接口,结果还要额外将 open()、close() 这两种功能也实现了,这样显然不合理呀。
而将这三个功能都声明在一个抽象类中,也会遇到上述的问题。
所以从这里可以看出,open() 、close() 和 alarm() 根本就属于两个不同范畴内的行为,open() 和 close() 是门本身固有的行为特性,而 alarm() 属于延伸的附加行为。因此最好的解决办法是单独将报警设计为一个接口,包含 alarm() 行为,Door 设计为单独的一个抽象类,包含 open 和 close 两种行为。再设计一个报警门继承 Door 类和实现 Alarm 接口。
interface Alram {
void alarm();
}
abstract class Door {
void open();
void close();
}
class AlarmDoor extends Door implements Alarm {
void oepn() {
//....
}
void close() {
//....
}
void alarm() {
//....
}
}
总结
不管使用抽象类还是接口,归根结底是为了尽可能地职责分离,把业务抽象,也就是“面向接口编程”。
参考抽象类的理解参考文章: 1.https://www.cnblogs.com/dolphin0520/p/3811437.html 2.https://blog.csdn.net/qq_45151158/article/details/123785005 3.https://blog.csdn.net/chenssy/article/details/12858267 4.https://www.runoob.com/w3cnote/java-abstract-interface-different.html
接口的理解参考文章: 1.https://blog.csdn.net/m0_61220535/article/details/123436292 2.https://blog.51cto.com/u_3664660/3214698 3.https://segmentfault.com/a/1190000040932698 4.https://zhuanlan.zhihu.com/p/271073878?ivk_sa=1024320u 5.https://gitbook.cn/books/5a237e8d508755657b690914/ 6.https://blog.csdn.net/qq_40587575/article/details/78793885 7.https://www.cnblogs.com/otakus/p/12169072.html 8.https://developer.51cto.com/article/469310.html 9.https://blog.csdn.net/kwame211/article/details/77374710 10.https://www.sohu.com/a/352592926_99950532 11.https://ld246.com/article/1552317815323