很多人有过这样的疑问:为什么有的地方必须使用接口而不是抽象类,而在另一些地方,又必须使用抽象类而不是接口呢?或者说,在考虑Java类的一般化问题时,很多人会在接口和抽象类之间犹豫不决,甚至随便选择一种。

实际上接口和抽象类的选择不是随心所欲的。 要理解接口和抽象类的选择原则,有两个概念很重要:对象的行为和对象的实现。如果一个实体可以有多种实现方式,则在设计实体行为的描述方式时,应当达到这样一个目标:在使用实体的时候,无需详细了解实体行为的实现方式。也就是说,要把对象的行为和对象的实现分离开来。既然Java的接口和抽象类都可以定义不提供具体实现的方法,在分离对象的行为和对象的实现时,到底应该使用接口还是使用抽象类呢?

通过抽象类建立行为模型

在接口和抽象类的选择上,必须遵守这样一个原则:行为模型应该总是通过接口而不是抽象类定义。为了说明其原因,下面试着通过抽象类建立行为模型,看看会出现什么问题。

假设要为销售部门设计一个软件,这个软件包含一个“发动机”(Motor)实体。显然无法在发动机对象中详细地描述发动机的方方面面,只能描述某些对当前软件来说重要的特征。至于发动机的哪些特征是重要的,则要与用户(销售部门)交流才能确定。

销售部门的人要求每一个发动机都有一个称为马力的参数。对于他们来说,这是惟一值得关心的参数。基于这一判断,可以把发动机的行为定义为以下行为。

行为1:查询发动机的马力,发动机将返回一个表示马力的整数。

虽然现在还不清楚发动机如何取得马力这个参数,但可以肯定发动机一定支持这个行为,而且这是所有发动机惟一值得关注的行为特征。这个行为特征既可以用接口定义,也可以用抽象类定义。为了说明用抽象类定义可能出现的问题,下面用抽象类建立发动机的行为模型,并用Java方法描述行为1,代码如下:

public abstract Motor{abstract public int getHorsepower();  }
在Motor抽象类的基础上构造出多种具体实现,例如A型发动机、B型发动机等,再加上系统的其它部分,最后得到1.0版的软件并交付使用。一段时间过去了,现在要设计2.0版的软件。在评估2.0版软件需求的过程中,发现一小部分发动机是电池驱动的,而电池需要一定的充电时间。销售部门的人希望能够通过计算机查阅充电时间。根据这一要求定义一个新的行为,如图1所示。

行为2:查询电驱动发动机的充电时间,发动机将返回一个表示充电时间的整数。

用Java方法来描述这个行为,代码如下:

public abstract BatteryPoweredMotor extends Motor{abstract public int getTimeToRecharge();}
在销售部门的软件中,电驱动发动机也以类的形式实现,但这些类从BatteryPoweredMotor而不是Motor派生。这些改动加入到2.0版软件之后,销售部门很满意。随着业务的不断发展,不久之后光驱动的发动机出现了。销售部门要求光驱动发动机需要一定光能才能运转,光能以流明(Lumen)度量。这个信息对客户很重要,因为下雨或多云的天气里,某些光驱动发动机可能无法运转。销售部门要求为软件增加对光驱动发动机的支持,所以要定义一个新的行为。

行为3:查询光驱动发动机能够正常运转所需要的最小流明数,发动机返回一个整数。

再定义一个抽象类并把行为3转换成Java方法,代码如下:

public abstract SolarPoweredMotor extends Motor{abstract public int getLumensToOperate();}

如图1所示,SolarPoweredMotor和BatteryPoweredMotor都从Motor抽象类派生。在整个软件中,90%以上的代码以相同的方式对待所有的发动机。偶尔需要检查一下发动机是光驱动还是电驱动,使用instanceof实现,代码如下:

if (instanceof SolarPoweredMotor){...} if (instanceof BatteryPoweredMotor){...}
无论是哪种发动机,马力这个参数都很重要,所以在所有派生的抽象类(SolarPoweredMotor和BatteryPoweredMotor)中,getHorsepower()方法都有效。

现在销售部门又有了一种新的发动机,它是一种既有电驱动又有光驱动的双重驱动发动机。光驱动和电驱动的行为本身没有变化,但新的发动机同时支持两种行为。在考虑如何定义新型的光电驱动发动机时,接口和抽象类的差别开始显示出来了。新的目标是在增加新型发动机的前提下尽量少改动代码。因为与光驱动发动机、电驱动发动机有关的代码已经过全面的测试,不存在已知的Bug。为了增加光电驱动发动机,要定义一个新的SolarBatteryPowered抽象类。如果让SolarBatteryPowered从Motor抽象类派生,SolarBatteryPowered将不支持针对光驱动发动机和电驱动发动机的instanceof操作。也就是说,如果查询一个光电驱动的发动机是光驱动的,还是电驱动的,得到的答案是:都不是。

如果让SolarBatteryPowered从SolarPoweredMotor(或BatteryPoweredMotor)抽象类派生,类似的问题也会出现,SolarBatteryPowered将不支持针对BatteryPoweredMotor(或SolarPoweredMotor)的instanceof操作。从行为上看,光电驱动的发动机必须同时从两个抽象类派生,但Java语言不允许多重继承。之所以会出现这个问题,根本的原因在于使用抽象类不仅意味着定义特定的行为,而且意味着定义实现的模式。也就是说,应该定义一个发动机如何获得行为的模型,而不仅仅是声明发动机具有某一个行为。

通过接口建立行为模型

如果用接口来建立行为模型,就可以避免隐含地规定实现模式。例如,前面的几个行为改用接口定义如下。

行为1:

public interface Motor(){public int getHorsepower();}
行为2:

public interface BatteryPoweredMotor extends Motor(){public int getTimeToRecharge();}
行为3:

public interface SolarPoweredMotor extends Motor{abstract public int getLumensToOperate();}
现在光电驱动的发动机可以描述为:

public DualPoweredMotor implements SolarPoweredMotor, BatteryPoweredMotor{}

DualPoweredMotor只继承行为定义,而不是行为的实现模式,如图2所示。

在使用接口的同时仍旧可以使用抽象类,不过这时抽象类的作用是实现行为,而不是定义行为。只要实现行为的类遵从接口定义,即使它改变了父抽象类,也不用改变其它代码与之交互的方式。特别是对于公用的实现代码,抽象类有它的优点。抽象类能够保证实现的层次关系,避免代码重复。然而,即使在使用抽象类的场合,也不要忽视通过接口定义行为模型的原则。从实践的角度来看,如果依赖于抽象类来定义行为,往往导致过于复杂的继承关系,而通过接口定义行为能够更有效地分离行为与实现,为代码的维护和修改带来方便。

职场 开发 休闲 java基础

0

分享

微博 QQ 微信

收藏

上一篇:javascript面向对象技术... 下一篇:Java中的instanceof...
ljh0242

444篇文章,265W+人气,1粉丝

关注

Ctrl+Enter 发布

发布

取消

1条评论

按时间倒序 按时间正序

推荐专栏更多

微服务技术架构和大数据治理实战

大数据时代的微服务之路

共18章 | 纯洁微笑

¥51.00 669人订阅

订   阅

基于Python的DevOps实战

自动化运维开发新概念

共20章 | 抚琴煮酒

¥51.00 428人订阅

订   阅

猜你喜欢

我的友情链接 js闭包的研究 Android开发学习笔记:浅谈WebView 发现大量的TIME_WAIT解决办法 Android开发学习笔记:Intent的简介以及属性的详解 vagrant打造自己的开发环境~~我也来一发 GNU开发工具——CMake快速入门 Jmeter之仿真高并发测试(集合点) Android 音视频开发入门指南 Android音频开发(1):基础知识 Android开发学习笔记:浅谈ToggleButton Python高级运维开发2016年7月第14期隆重开课 Spring Boot 中 10 行代码构建 RESTful 风格应用 Java核心库实现AOP过程 RabbitMQ如何保证队列里的消息99.99%被消费? 几种简单的负载均衡算法及其Java代码实现 RabbitMQ如何保证消息99.99%被发送成功? IT兄弟连 JavaWeb教程 经典案例 在阿里架构师眼中构建一个较为通用的业务技术架构就是如此简单 Spring Boot 整合 Mybatis 的完整 Web 案例

扫一扫,领取大礼包

0

1

分享

关注

ljh0242

转载于:https://blog.51cto.com/77857/141429

选择Java接口还是抽象类相关推荐

  1. 什么时候使用接口?什么时候使用抽象?选择Java接口还是抽象类 (转)

    老帖了,但是还是想自己收录一下.最后也把自己对于这个问题的一些粗糙的理解记录下来. 在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的.在这种情况下,各个对象内部是如何实现自己的对 ...

  2. java接口和抽象类的区别(经典面试题)

    java接口和抽象类的区别(经典面试题) 要了解接口和抽象类的区别,首先需要明白接口和抽象类的定义. 1.抽象类 包含抽象方法的类称为抽象类,但并不意味着抽象类中只能有抽象方法,它和普通类一样,同样可 ...

  3. java接口和抽象类的区别和作用

    java接口和抽象类的区别和作用 接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明.一个类通过(implements)接口的方 ...

  4. java 接口与抽象类的区别

    1.概述 一个软件设计的好坏,我想很大程度上取决于它的整体架构,而这个整体架构其实就是你对整个宏观商业业务的抽象框架,当代表业务逻辑的高层抽象层结构 合理时,你底层的具体实现需要考虑的就仅仅是一些算法 ...

  5. Java 接口和抽象类可以被new么?

    背景: 最近有同事跟我说了他面试时遇到的问题,考官问:"接口和抽象类可以被new嘛?".这可能不是考官的原话,但是据他表达考官大概就是这个意思了.听到这个问题,我的第一反应是肯定不 ...

  6. Java 接口和抽象类可以被new么?——顺便总结内部类

    转载:https://blog.csdn.net/hackersaillen/article/details/47281549 背景: 最近有同事跟我说了他面试时遇到的问题,考官问:"接口和 ...

  7. java 接口和抽象类的区别6_JAVA基础篇-接口和抽象类的区别

    .前言 JAVA是一种面向对象语言,具备抽象(Abstract),封装(packing),继承(extends),多态(polymorphic)四大特性. 我们重点从oop思想∠来分析. .在面向对象 ...

  8. 抽象类中不能有private的成员_【java基础】-- java接口和抽象类的异同分析

    在java中,通常初学者搞不懂接口与抽象类,这也是面试比较容易问到的一个问题.下面我来谈谈自己的理解.如有不妥之处,还望批评指正,不胜感激. 1.抽象类怎么定义和继承? 2.接口怎么定义和实现? 3. ...

  9. 通过实例讲解java接口和抽象类的特殊实现方法

    一.java中的接口本质上是加约束的抽象类 //抽象类 public abstract class AExample { public abstract int add(int x,int y): p ...

最新文章

  1. ffmpeg硬解码视频文件播放器
  2. Linux查看端口使用状态及启动
  3. 格“物”致知:多模态预训练再次入门
  4. php安装文件怎么打开文件_php文件如何打开
  5. Linux C高级编程——网络编程基础(1)
  6. attribute property --- jquery attr() prop()
  7. is present but cannot be translated into a null value due to being declared as a primitive type
  8. mybatis基础,mybatis核心配置文件properties元素
  9. [UE4]编辑器偏好设置,在同一个窗口以标签打开蓝图
  10. POJ - 3494
  11. LOJ#6038. 「雅礼集训 2017 Day5」远行(LCT)
  12. Atitit 为什么oracle这类大型数据库比mysql的性能机制目录1. 分区机制差别 11.1. Join算
  13. SqlServer 获取工作日(周六、周日休息,周六日不休息,周六不休息)
  14. IT忍者神龟之 配额不足的解决方法ORA-01536: space quota exceeded for tablespace
  15. 移动开发采用什么平台好?
  16. 【听】蔡康永的说话之道,说话的技巧方法论
  17. win10 系统更新服务器出错怎么办,解决更新win10系统出现错误提示“0x800f081f”的方法...
  18. TK-StringVar
  19. 树的重心——DFS求解
  20. win7 如何卸载mysql_Win7如何彻底卸载sql2005?

热门文章

  1. 5种数据同分布的检测方法!
  2. PostgreSQL_row_number() over()
  3. 7年秘密研发,Meta拿下元宇宙「登月项目」!气动手套让指尖有真实触感
  4. 拖拽公式图片、一键转换LaTex公式,这款开源公式识别神器比Mathpix Snip更适合你...
  5. 超越PVT、Swin,南大开源高效Transformer:ResT​
  6. 寒武纪首颗AI训练芯片亮相
  7. NeurIPS 2020 :新一代算法“鉴黄师”诞生,中科院计算所研究生一作
  8. 论文LaTeX、项目README:无脑套用格式、开源模板最高10万赞
  9. Django视图之HttpRequest对象和HttpResponse对象
  10. K-近邻算法之kd树