当前位置: 首页 > news >正文

第二十条:与抽象类相比,优先选择接口

要定义多种实现的类型:JAVA有两种机制:接口和抽象类。这两种机制都支持为某些实例方法提供实现,但二者有个重要的区别:要实现由抽象类定义的类型,这个类必须是抽象类的子类。因为Java只允许单继承,对抽象类的这种限制严重制约了将其用于类型的定义。而接口就宽松很多,只要定义了所有必须的方法,任何类都可以实现。

在正式介绍之前普及两个知识点:缺省方法和抽象方法。

这两个方法是相反的用途:缺省是为了避免子类重写其方法。抽象方法是为了让子类重写方法。

缺省方法(default)案例:

public interface SoyaMilk2 {default void select() {System.out.println("选择");}
}

子类:

public class RedInter implements SoyaMilk2 {}

抽象方法案例:

public interface SoyaMilk2 {abstract void addCondiments();}

子类:

接口优先于抽象类优点:

1.很容易改造现有的类使其实现一个新的接口。

2.接口是定义minxin(混合类型)的理想选择。

3.接口允许构建非层次结构的类型框架。

案例:

public interface Singer {//唱歌AudioClip sing(Song s);
}public interface SongWriter {//作歌Song compose(boolean hit);
}
public intreface SingerSongWriter extends Singer, SongWriter {//弹奏AudioClip strum();//激情表演void actSensitive();
}

抽象类:

Singer.java
public abstract class Singer {//唱歌public abstract AudioClip sing(Song s);
}SongWriter.java
public abstract class SongWriter {//作歌public abstract Song compose(boolean hit);
}SingerSongWriter.java
//在设计的时候感觉很不好设计。因为继承只能继承自一个类,那势必其他的方法需要重新声明
public abstract class SingerSongWriter extends SongWriter {//唱歌public abstract AudioClip sing(Song s);//弹奏public abstract AudioClip strum();//激情表演public abstract void actSensitive();
}

在引入抽象骨架概念之前,先分别看下接口和抽象类的案例实现:

(1)接口案例:

定义接口:

public interface IPeple {void drink();void eat();void ethnicGroup();}

分别定义子类:

public class AsiaPeple implements IPeple {@Overridepublic void drink() {System.out.println("人都会喝水");}@Overridepublic void eat() {System.out.println("人都会吃饭");}@Overridepublic void ethnicGroup() {System.out.println("亚洲人大多数是黄种人");}
}
public class AmericanPeple implements IPeple {@Overridepublic void drink() {System.out.println("人都会喝水");}@Overridepublic void eat() {System.out.println("人都会吃饭");}@Overridepublic void ethnicGroup() {System.out.println("美洲人大多数是白种人");}
}

问题:

drink和eat方法代码重复性很高,需要改造。

(2)抽象类案例:

定义抽象类:

public abstract class AbsPeple {void drink(){System.out.println("人都会喝水");}void eat() {System.out.println("人都会吃饭");}abstract void ethnicGroup();
}

分别定义子类:

public class AmericanPeple extends AbsPeple {@Overridevoid ethnicGroup() {System.out.println("美洲人大多数是白种人");}
}

public class AsiaPeple extends AbsPeple{@Overridevoid ethnicGroup() {System.out.println("亚洲人大多数是黄种人");}public static void main(String[] args) {AsiaPeple asiaPeple = new AsiaPeple();asiaPeple.eat();asiaPeple.drink();asiaPeple.ethnicGroup();AmericanPeple americanPeple = new AmericanPeple();americanPeple.eat();americanPeple.drink();americanPeple.ethnicGroup();System.out.println(asiaPeple);System.out.println(americanPeple);}
}

结果打印:

人都会吃饭
人都会喝水
亚洲人大多数是黄种人
人都会吃饭
人都会喝水
美洲人大多数是白种人
com.example.exceldemo.abstact.entity.AsiaPeple@7699a589
com.example.exceldemo.abstact.entity.AmericanPeple@58372a00

缺点:一旦一个类继承了抽象类AbsPeple,那么它就无法继承其它类。而且我们也知道,继承实现有很多问题,太多的继承会造成代码耦合性问题,不利于以后的维护和升级。抽象骨架氤氲而生。

(3)抽象骨架概念:(抽象类继承接口,不要求重写接口中缺省、抽象方法)

可以将接口和抽象类的优点结合到一起。其中,接口用来定义类型,可能还会提供一些默认的方法,而骨架实现类负责在基本接口方法之上实现其余的非基本接口方法(ethnicGroup()方法)。扩展骨架实现类可以省去实现接口需要的大部分工作。这就是模板方法【设计模式】(中级面试很多面试官喜欢问设计模式)

定义抽象骨架:

public abstract class AbsPeple implements IPeple{@Overridepublic void drink() {System.out.println("人都要喝水");}@Overridepublic void eat() {System.out.println("人都要吃饭");}
}

定义私有类及成员(AsiaPeple重写接口统一方法,成员变量获取单独的重写方法):

public class AsiaPeple implements IPeple {private AsiaPepleIpml asiaPepleIpml = new AsiaPepleIpml();private static class AsiaPepleIpml extends AbsPeple {@Overridepublic void ethnicGroup() {System.out.println("亚洲人大多数都是黄种人");}}public static void main(String[] args) {AsiaPeple asiaPeple = new AsiaPeple();asiaPeple.eat();asiaPeple.drink();asiaPeple.asiaPepleIpml.ethnicGroup();}@Overridepublic void drink() {asiaPepleIpml.drink();}@Overridepublic void eat() {asiaPepleIpml.eat();}@Overridepublic void ethnicGroup() {throw new UnsupportedOperationException("不重新方法");}
}

打印结果:

人都要吃饭
人都要喝水
亚洲人大多数都是黄种人Process finished with exit code 0

AsiaPeple类 可以实现多个接口和定义多个抽象骨架实现类,使得AsiaPeple类非常非常灵活多变。

骨架实现类的美妙在于,他们提供了抽象类的所有实现帮助,又不存在将抽象类用于类型定义时所面临的严格限制。接口本身存在的任何默认方法,对于这个类还是有帮助的。此外,仍然可以利用骨架实现来帮助实现者完成任务:实现该接口的类可以引入一个私有的、扩展了骨架实现类的内部类,并包含一个这个内部类实例,然后将对接口方法的调用转发给这个实例。这种技术被称为模拟多重继承。

因为骨架实现是为了继承而设计的,好的文档在骨架实现中是绝对必要的,无论它是由接口上的默认方法组成还是单独的抽象类。

总而言之,要定义支持实现的类型,接口通常是最佳选择如果导出一个不是很简单的接口,请务必考虑配合提供一个骨架实现。在可能的情况下,应该通过接口上的默认方法来提供骨架的实现,以便该接口的所有实现者都可以使用。即便如此,接口上的限制常会使得抽象类形式成为骨架实现的不二之选。

所有文章无条件开放,顺手点个赞不为过吧!

                                                               

相关文章:

  • 程序员需要具备的核心竞争力
  • 【等保2.0是什么意思?等保2.0的基本要求有哪些? 】
  • 游戏中的坐标转换函数*2(laya2D)
  • JVM的五大内存区域
  • AGI 之 【Hugging Face】 的【Transformer】的 [ Transformer 架构 ] / [ 编码器 ]的简单整理
  • 【python】OpenCV—Nighttime Low Illumination Image Enhancement
  • 1.1.2数据结构的三要素
  • 将带有 商店idr 商品信息的json导入到mongodb后,能不能根据商店id把所有商品全部提取并转为电子表格
  • 基于Echarts进行图表组件的封装
  • 在Linux/Debian/Ubuntu中出现“Could not get lock /var/lib/dpkg/lock-frontend”问题的解决办法
  • maven项目、idea抽风问题解决
  • 【React性能优化】父组件渲染如何避免子组件不必要的渲染
  • xcrun: error: unable to find utility “simctl“, not a developer tool or in PATH
  • 从硬件角度看Linux的内存管理
  • Map Set(Java篇详解)
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • 4个实用的微服务测试策略
  • AngularJS指令开发(1)——参数详解
  • CentOS6 编译安装 redis-3.2.3
  • css系列之关于字体的事
  • ES10 特性的完整指南
  • Java知识点总结(JDBC-连接步骤及CRUD)
  • js算法-归并排序(merge_sort)
  • js写一个简单的选项卡
  • MySQL主从复制读写分离及奇怪的问题
  • OpenStack安装流程(juno版)- 添加网络服务(neutron)- controller节点
  • Rancher如何对接Ceph-RBD块存储
  • Redux 中间件分析
  • Spring Security中异常上抛机制及对于转型处理的一些感悟
  • vue的全局变量和全局拦截请求器
  • Webpack 4 学习01(基础配置)
  • 动态规划入门(以爬楼梯为例)
  • 详解移动APP与web APP的区别
  • 想写好前端,先练好内功
  • - 语言经验 - 《c++的高性能内存管理库tcmalloc和jemalloc》
  • 《码出高效》学习笔记与书中错误记录
  • 基于django的视频点播网站开发-step3-注册登录功能 ...
  • 数据库巡检项
  • ​ssh-keyscan命令--Linux命令应用大词典729个命令解读
  • # .NET Framework中使用命名管道进行进程间通信
  • #我与Java虚拟机的故事#连载13:有这本书就够了
  • (1)STL算法之遍历容器
  • (145)光线追踪距离场柔和阴影
  • (17)Hive ——MR任务的map与reduce个数由什么决定?
  • (C语言)球球大作战
  • (react踩过的坑)Antd Select(设置了labelInValue)在FormItem中initialValue的问题
  • (八)光盘的挂载与解挂、挂载CentOS镜像、rpm安装软件详细学习笔记
  • (翻译)terry crowley: 写给程序员
  • (附源码)springboot家庭财务分析系统 毕业设计641323
  • (六)库存超卖案例实战——使用mysql分布式锁解决“超卖”问题
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理 第13章 项目资源管理(七)
  • (三十五)大数据实战——Superset可视化平台搭建
  • (深度全面解析)ChatGPT的重大更新给创业者带来了哪些红利机会
  • (五)c52学习之旅-静态数码管
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解