草庐IT

基于接口而非实现编程

程序员翔仔 2023-03-28 原文

抽象类和接口的区别

在面向对象编程当中,抽象类和接口是为抽象而生而的两个概念,在初学时特别容易搞混它们俩。

Java 既支持接口,也支持抽象类,这里主要拿 Java 的接口和抽象类做比较。简单地在 Java 中定义这两个概念就是,抽象类是包含抽象方法的类,接口是对行为的抽象。

抽象类

在 Java 中,抽象类仍然以 class 定义,并在此基础上增加 abstract 修饰,如下是抽象类的定义:

[public|protected] abstract class ClassName {
    abstract void fun();
}

从定义上看,Java 中的抽象类就是用来继承的,没有被继承的抽象类没有任何实际的作用。而且,抽象类中的抽象方法只是起到一个限制的作用,并没有提供实际的方法体,这也要求子类去实现自己的方法体。

将抽象类的特征总结一下,大概有以下几点:

  • 抽象类不允许被实例化,只能被继承
  • 抽象类可以包含属性和方法,方法里既可以包含具体实现,也可以不包含具体实现,不包含具体实现的方法称为抽象方法
  • 子类继承抽象类,必须实现抽象类的所有抽象方法

接口

在 Java 中,接口以 interface 定义,与 class 定义的类不同,如下是接口的定义:

[public|protected] interface InterfaceName {
    void func();
}

接口实际上也可以包含变量和方法,但是,接口中的变量会被隐式地指定为 public static final 修饰的不可变量,接口中的方法会被隐式地指定为 public abstract 修饰的方法。

将接口的特性总结一下,大概有以下几点:

  • 接口不能声明属性,可以声明的是静态变量
  • 接口声明的方法不包含具体实现
  • 类实现接口的时候,必须实现接口中声明的所有方法

区别

从上述对抽象类和接口的简单分析看,抽象类和接口的概念非常相似,从明面上看,其最大的区别就是,抽象类是用来继承的,接口是用来实现的。

从更深层次的角度上看,抽象类是不能被实例化的类,只能被子类继承,继承关系表示的是一种 is-A 的关系,接口表示的是一种 has-A 关系。

在使用时,抽象类可以定义一些公共的属性、方法,抽象方法用于声明子类继承的约束;接口的主要作用就是声明实现的协议,但是相比抽象类的优势就是一个类可以实现多个接口。

抽象类和接口的使用

抽象类的使用

首先,只能被子类继承的抽象类能解决代码复用的问题。

然后,抽象类表达的是一种抽象概念,适用于表示现实生活中的抽象概念。如狗是具体对象,动物则是抽象概念。

使用抽象方法,而非空的方法体,创建子类时就知道他必须要重写该方法,而不能忽略。

使用抽象类,类的使用者创建对象的时候,就知道他必须要使用某个具体子类,而不是抽象类本身。

使用抽象类提高了安全性,降低了开发者犯错的概率,是一种更优雅的编码方式。

抽象类更多的作用是引导使用者正确使用,避免被误用。

接口的使用

接口是对行为的一种抽象,相当于一组协议,更侧重于解耦。

调用者只需要关注抽象的接口,不需要了解具体的实现,具体的实现代码对调用者透明。接口实现了约定和实现相分离,可以降低代码间的耦合,提高代码的扩展性。

配合使用

如果抽象类只定义抽象方法,那抽象类和接口非常相似。但接口和抽象类在根本上是不同的,一个类可以实现多个接口,但只能继承一个类。

抽象类和接口是配合而不是替代,它们经常一起使用,接口声明能力,抽象类提供默认实现,实现全部或部分方法,一个接口经常有一个对应的抽象类。

比如,在 Java 类库中有以下关系:

  • Collection 接口和对应的 AbstractCollection 抽象类
  • List 接口和对应的 AbstractList 抽象类
  • Map 接口和对应的 AbstractMap 抽象类

模拟抽象类和接口

通过抽象类实现接口

接口没有成员变量,没有方法实现,只有方法声明,实现接口的类必须实现接口中的所有方法。

只要满足上述几个特点,从设计的角度上讲,它就可以叫作接口。

在 Java 中,使用抽象类实现起来也比较简单,即抽象类只定义抽象方法即可,缺陷就是子类无法继承多个抽象类。

用普通类模拟接口

普通的类是可以包含具体实现的,这不符合接口的定义。但是,可以让类中的方法抛出 NoSuchMethodError 错误来模拟不包含实现的接口,并且强迫子类在继承这个父类时都去主动实现父类的方法,否则就会在运行时抛出异常。

为了避免普通的类被实例化,需要将这个类的构造函数声明成 protected 访问权限。

具体的代码实现如下:

public class MockInterface {
    protected MockInterface() {}

    public void funcA() {
        throw new NoSuchMethodError();
    }
}

同样的,无论是使用抽象类还是普通类,实现的接口都无法满足接口的所有特性,这里也仅做一些了解。

基于接口而非实现编程

在软件开发中,最大的挑战之一就是需求的不断变化,因此,开发时一定要具有抽象意识、封装意识、接口意识。

越抽象、越顶层、越脱离具体某一实现的设计,越能提高代码的灵活性、扩展性、可维护性。

这个时候,接口的存在就非常必要了,通过使用接口定义实现类的协议,将约定和实现分离,做到了解耦的效果。

在定义接口的时候,一些注意事项就是:命名一定要足够通用,不能包含跟具体实现相关的字眼;另一方面,与特定实现相关的方法不要定义在接口中。

通常,越是不稳定的系统,越是要在代码的扩展性、维护性上下功夫。相反,某个系统特别稳定,在开发完成之后,基本不需要做维护,则没有必要为其扩展性、维护性投入不必要的开发时间。

有关基于接口而非实现编程的更多相关文章

  1. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  2. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

  3. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

    导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

  4. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  5. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  6. 网络编程套接字 - 2

    网络编程套接字网络编程基础知识理解源`IP`地址和目的`IP`地址理解源MAC地址和目的MAC地址认识端口号理解端口号和进程ID理解源端口号和目的端口号认识`TCP`协议认识`UDP`协议网络字节序socket编程接口`sockaddr``UDP`网络程序服务器端代码逻辑:需要用到的接口服务器端代码`udp`客户端代码逻辑`udp`客户端代码`TCP`网络程序服务器代码逻辑多个版本服务器单进程版本多进程版本多线程版本线程池版本服务器端代码客户端代码逻辑客户端代码TCP协议通讯流程TCP协议的客户端/服务器程序流程三次握手(建立连接)数据传输四次挥手(断开连接)TCP和UDP对比网络编程基础知识

  7. postman接口测试工具-基础使用教程 - 2

    1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,

  8. MIMO-OFDM无线通信技术及MATLAB实现(1)无线信道:传播和衰落 - 2

     MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO

  9. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  10. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

随机推荐