抽象类实现接口的意义


前言

抽象类和接口其实都是抽象的一种,那么他俩有何异同呢?
抽象类实现接口的意义何在?


一、抽象类和接口对比

  1. 接口大家比较熟悉,它其实是一种规范,规定了方法的入参,反参等,一种抽象, 关键字是 interface;
  2. 抽象类是用 abstract 修饰的类,可以包含抽象方法,也可以不包含抽象方法,可以有普通方法
  3. 一般来说接口中的方法都是抽象的,无方法体的,但是java8之后,增加了default (大家课后了解下),它让接口也可以有方法体了,那么其实这里的default 就增强了接口的功能,不逊于抽象类了;
  4. 接口是用来实现的,而且实现一个接口的时候,子类必须实现接口中的所有方法
  5. 抽象类是用来被继承的,抽象类中的抽象方法可以在子类中选择性实现,这就是抽象类的灵活性
  6. 那么当我用抽象类实现接口,我可以选择某些方法我在抽象类中实现,某些方法我不实现,而是继续在抽象类的子类中实现,那么这个方法我虽然实现了,但是还是一个抽象方法(你以为我实现了,然后并没有)

没有代码,仅讲解的的博主相当于耍流氓,接下来进入代码环节

二、举例说明三种情况

1.接口实现类

使用场景: 我又两种支付方式,微信/支付宝, 为了统一对外逻辑,我弄成一个接口对外暴露,方便统一调用

接口

public interface PayService {

    /**
     * 获取支付具体实现
     *
     * @return
     */
    String getType();

    /**
     * 具体支付方法
     *
     * @param order
     * @param money
     * @return
     */
    String toPay(String order, Integer money);
}

### 实现类
```java 
@Service
public class AliPayServiceImpl implements PayService {
    /**
     * 获取支付具体实现
     *
     * @return
     */
    @Override
    public String getType() {
        return "Ali";
    }

    /**
     * 具体支付方法
     *
     * @param order
     * @param money
     * @return
     */
    @Override
    public String toPay(String order, Integer money) {
        System.out.println("阿里支付用支付宝,优惠一元");
        return "Ali支付 订单号: " + order + " 金额: " + (money - 1);
    }
}

// =======================================================

@Service
public class WxPayServiceImpl implements PayService {
    /**
     * 获取支付具体实现
     *
     * @return
     */
    @Override
    public String getType() {
        return "Wx";
    }

    /**
     * 具体支付方法
     *
     * @param order
     * @param money
     * @return
     */
    @Override
    public String toPay(String order, Integer money) {
        System.out.println("微信支付,原价支付");
        return "Wx支付 订单号: " + order + " 金额: " + money;
    }
}

2.抽象类实现类

使用场景: 依然是第一个支付场景,我这里简单改造下;抽象类还能有普通方法,这里我增加一个支付打印

抽象类

public abstract class PayService {

    /**
     * 获取支付具体实现
     *
     * @return
     */
    abstract String getType();

    /**
     * 具体支付方法
     *
     * @param order
     * @param money
     * @return
     */
    abstract String toPay(String order, Integer money);


    /**
     * 支付成功打印
     */
    public void sout(){
        System.out.println("我支付成功了");
    }
}

实现类(子类)

@Service
public class AliPayServiceImpl extends PayService {
    /**
     * 获取支付具体实现
     *
     * @return
     */
    @Override
    public String getType() {
        return "Ali";
    }

    /**
     * 具体支付方法
     *
     * @param order
     * @param money
     * @return
     */
    @Override
    public String toPay(String order, Integer money) {
        System.out.println("阿里支付用支付宝,优惠一元");
        return "Ali支付 订单号: " + order + " 金额: " + (money - 1);
    }
}

// =========================================================
@Service
public class WxPayServiceImpl extends PayService {
    /**
     * 获取支付具体实现
     *
     * @return
     */
    @Override
    public String getType() {
        return "Wx";
    }

    /**
     * 具体支付方法
     *
     * @param order
     * @param money
     * @return
     */
    @Override
    public String toPay(String order, Integer money) {
        System.out.println("微信支付,原价支付");
        return "Wx支付 订单号: " + order + " 金额: " + money;
    }
}

这里看完是不是觉得抽象比接口强大,那为什么还要接口呢?

  • 接口可以解决多重继承问题,提供更灵活的扩展和维护
  • Java中的抽象类和接口各有其应用场景,抽象类和接口都可以定义规范,但实现规范的方式不同。抽象类是具体实现的规范,而接口是行为的规范。
  • 抽象类可以解决单继承局限,避免多继承带来的复杂性和低效性

3.抽象类实现接口

使用场景: 仍然是支付场景,接口中定义了四个方法 (abcd),有三个实现类 A B C ;
其中A 需要实现 ab d, B需要实现 bc d, C需要实现ca d
也就是A B C 三个实现类不需要实现接口中的所有方法,但是都需要实现d方法,而且是一个逻辑
这里d方法在每个子类中都实现一遍没必要,重复代码,咋办呢? 我们在接口和实现类之间加一个 抽象类

接口

public interface PayService {

    /**
     * 获取支付具体实现
     *
     * @return
     */
    String getType();

    /**
     * 具体支付方法
     *
     * @param order
     * @param money
     * @return
     */
    String toPay(String order, Integer money);


    /**
     * 扣减库存
     * @param num 购买数量
     * @return
     */
    int decreaseStash(int num);

    /**
     * 打印成支付
     */
    void sout();

}

抽象类

public abstract class PayAbstract implements PayService{

    /**
     * 获取支付具体实现
     *
     * @return
     */
    @Override
    public String getType() {
        return null;
    }

    /**
     * 具体支付方法
     *
     * @param order
     * @param money
     * @return
     */
    @Override
    public String toPay(String order, Integer money) {
        return null;
    }

    /**
     * 扣减库存
     *
     * @param num 购买数量
     * @return
     */
    @Override
    public int decreaseStash(int num) {
        return 0;
    }

    /**
     * 打印成支付
     */
    @Override
    public void sout() {
        System.out.println("支付成功");
    }
}

三个实现类

@Service
public class AliPayServiceImpl extends PayAbstract {
    /**
     * 获取支付具体实现
     *
     * @return
     */
    @Override
    public String getType() {
        return "Ali";
    }

    /**
     * 具体支付方法
     *
     * @param order
     * @param money
     * @return
     */
    @Override
    public String toPay(String order, Integer money) {
        System.out.println("阿里支付用支付宝,优惠一元");
        return "Ali支付 订单号: " + order + " 金额: " + (money - 1);
    }
}

// ============================================================
@Service
public class WxPayServiceImpl extends PayAbstract {

    /**
     * 具体支付方法
     *
     * @param order
     * @param money
     * @return
     */
    @Override
    public String toPay(String order, Integer money) {
        System.out.println("微信支付,原价支付");
        return "Wx支付 订单号: " + order + " 金额: " + money;
    }

    /**
     * 扣减库存
     *
     * @param num 购买数量
     * @return
     */
    @Override
    public int decreaseStash(int num) {
        return num;
    }
}

// ============================================================

@Service
public class JUHEPayServiceImpl extends PayAbstract {

    /**
     * 获取支付具体实现
     *
     * @return
     */
    @Override
    public String getType() {
        return "JUHE";
    }

    /**
     * 扣减库存
     *
     * @param num 购买数量
     * @return
     */
    @Override
    public int decreaseStash(int num) {
        return num;
    }
}

这样在接口和抽象类之间又做了一层抽象,抽象层提取了公共的方法d (sout),而且让每个实现类都更加灵活的实现方法


总结

抽象类实现接口的意义在于提供了一种灵活且层次分明的代码结构,有助于实现模块化和可维护性。

具体来说,抽象类可以作为继承层次结构中的基础类,提供一些公共方法和属性,子类可以继承和扩展。而接口则定义了一组相关的方法规范,约束了实现这些方法的类或抽象类的行为。这有助于确保代码的模块化,提高代码的可重用性和可维护性。

抽象类相当于在原有抽象的基础上,再次抽象,提取了一些公共方法;

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
接口抽象类的区别 抽象方法是必须实现的方法。就象动物都要呼吸。但是鱼用鳃呼吸,猪用肺呼吸。 动物类要有呼吸方法。怎么呼吸就是子类的事了。 现在有很多讨论和建议提倡用interface代替abstract类,两者从理论上可以做一般性的混用,但是在实际应用中,他们还是有一定区别的。抽象类一般作为公共的父类为子类的扩展提供基础,这里的扩展包括了属性上和行为上的。而接口一般来说不考虑属性,只考虑方法,使得子类可以自由的填补或者扩展接口所定义的方法,就像JAVA王子所说的事件中的适配器就是一个很好的应用。 用一个简单的例子,比如说一个教师,我们把它作为一个抽象类,有自己的属性,比如说年龄,教育程度,教师编号等等,而教师也是分很多种类的,我们就可以继承教师类而扩展特有的种类属性,而普遍属性已经直接继承了下来。 而接口呢~还是拿教师做例子,教师的行为很多,除了和普通人相同的以外,还有职业相关的行为,比如改考卷,讲课等等,我们把这些行为定义成无body的方法,作为一个集合,它是一个interface。而教师张三李四的各自行为特点又有不同,那么他们就可以扩展自己的行为body。从这点意义上来说,interface偏重于行为。 总之,在许多情况下,接口确实可以代替抽象类,如果你不需要刻意表达属性上的继承的话。
抽象类接口的区别 【概述】 一个软件设计的好坏,我想很大程度上取决于它的整体架构, 而这个整体架构其实就是你对整个宏观商业业务的抽象框架,当代表业务逻辑的高层抽象层结构 合理时, 你底层的具体实现需要考虑的就仅仅是一些算法和一些具体的业务实现了。 当你需要再开发另一个相近的项目时,你以前的抽象层说不定还可以再次利用 。 面向对象的设计,复用的重点其实应该是抽象层的复用,而不是具体某一个代码块的复用。 在 面向对象的概念中,我们知道所有的对象都是通过类来描绘的,但是反过来却不是这样。 并不是 所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象, 这样的类就是抽象类抽象类往往用来表征我们在对问题领域进行分析、 设计中得出的抽象概念, 是对一系列看上去不同,但是本质上相同的具体概念的抽象。 比如:如果我们进行一个图形编辑软件的开发,就会发现问题领域存在着圆、 三角形这样一些具体概念, 它们是不同的,但是它们又都属于形状这样一个概念,形状这个概念在问题领域是不存在的, 它就是一个抽象概念。正是因为抽象的概念 在问题领域没有对应的具体概念, 所以用以表征抽象概念的抽象类是不能够实例化的。 在面向对象领域,抽象类主要用来进行类型隐藏。 我们可以构造出一个固定的一组行为的抽象描 述, 但是这组行为却能够有任意个可能的具体实现方式。这个抽象描述就是抽象类, 对于面向对象编程来说,抽象是它的一大特征之一。在Java中,可以通过两种形式来体现OOP(Object Oriented Programming,OOP,面向对象程序设计)的抽象:接口抽象类。 这两者有太多相似的地方,又有太多不同的地方。很多人在初学的时候会以为它们可以随意互换使用,但是实际则不然。 今天我们就一起来学习一下Java中的接口抽象类。 【抽象类】 在了解抽象类之前,先来了解一下抽象方法。 抽象方法是一种特殊的方法:它只有声明,而没有具体的实现。抽象方法的声明格式为: abstract void fun(); 抽象方法必须用abstract关键字进行修饰。如果一个类含有抽象方法,则称这个类为抽象类抽象类必须在类前用abstract关键字修饰。因为抽象类中含有无具体实现的方法,所以不能用抽象类创建对象。 抽象类不一定必须含有抽象方法。比如: 复制代码 public abstract class Dog { //普通方法 void bark() { } //抽象方法 abstract void Play(); } 复制代码 [public] abstract class ClassName { abstract void fun(); } 从这里可以看出,抽象类就是为了继承而存在的,如果你定义了一个抽象类,却不去继承它, 那么等于白白创建了这个抽象类,因为你不能用它来做任何事情。对于一个父类, 如果它的某个方法在父类中实现出来没有任何意义,必须根据子类的实际需求来进行不同的实现, 那么就可以将这个方法声明为abstract方法,此时这个类也就成为abstract类了。   包含抽象方法的类称为抽象类,但并不意味着抽象类中只能有抽象方法,它和普通类一样, 同样可以拥有成员变量和普通的成员方法。注意,抽象类和普通类的主要有三点区别:   1)抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法), 缺省情况下默认为public。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寂寞旅行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值