zoukankan      html  css  js  c++  java
  • 这一次,让你彻底明白接口及抽象类

    本文的目的是讨论抽象类和接口的作用、示例和使用场景,这是我的理解和总结。对于接口和抽象类的更多概念性知识,你可以自己参考相关文档。

    1. 抽象类及其作用

    抽象类,顾名思义,即类的抽象。

    当引入面向对象的概念时,我们知道类是客观事物的抽象,抽象类是类的进一步抽象。如何理解它们?

    例如,我们定义了宝马、奔驰和奥迪三大类,并分别抽象出宝马、梅赛德斯-奔驰和奥迪这三类车辆,包括相关的属性和行为(即方法)。但我们知道,汽车具有一般属性和行为,如品牌、发动机、方向盘、轮胎、前向、后退、转向等。因此,我们可以进一步抽象出宝马、梅赛德斯-奔驰等汽车上的“汽车”类的抽象类,包括一般特征(属性和侧面)。Law)让宝马、奔驰、奥迪继承抽象类扩展汽车,它们具有汽车的一般特征,然后在抽象类的基础上定义自己的特殊属性和方法。

    这里的 abstract class Car 即抽象类,可以看出,抽象类是用来捕捉子类的通用特性的,包括属性及行为

    2. 接口及其作用

    让我们看一下界面。如果我开发了一款叫Bote Royce的飞车,它的定义如下:

     1 class BoteRoyce extends Car {
     2     //...省略通用特性
     3 
     4     /**
     5      * 可以飞
     6      */
     7     void fly() {
     8         System.out.println("假装会飞~");
     9     }
    10 }

    看起来没问题:

    • BoteRoyce extends Car:表达这是一辆汽车;
    • fly() 方法:体现这车可以飞。

    但是,随着技术发展,出现了众多可以制造飞行汽车的厂商,难道每一个可以飞的汽车都去定义一个 fly() 方法?

    心想这还不简单,在抽象类 Car 中定义一个抽象方法 abstract void fly() 让子类去实现,不就可以了吗?

    不不不…并非所有的牛奶都被称为Trensu,不是所有的汽车都能飞。飞行不是汽车的一般特征。在Car中定义.()方法显然违反了使用抽象类捕获子类的一般特征的原则。

    在这种场景下,解决方案之一就是使用接口,如下:

    1 /**
    2  * 飞行器接口
    3  */
    4 public interface Aircraft {
    5     //定义抽象方法
    6     void fly();
    7 }

    BoteRoyce 的定义修改如下:

     1 /*
     2  * 实现 Aircraft 接口,表示具备飞行器能力
     3  */
     4 class BoteRoyce extends Car implements Aircraft {
     5 
     6     /**
     7      * 覆写接口方法,实现飞行能力
     8      */
     9     @Override
    10     void fly() {
    11         System.out.println("假装会飞~");
    12     }
    13 }

    再有其他品牌的飞行汽车,都可以通过 extends Car implements Aircraft 实现飞行能力。

    上述定义的 interface Aircraft 即为接口,我们通常使用接口对行为进行抽象

    3. 接口和抽象类的区别

    关于二者的区别,可以结合前面的例子,来加深理解。

    抽象类是对类本质的抽象,表达的是 is a 的关系,比如:BMW is a Car。抽象类包含并实现子类的通用特性,将子类存在差异化的特性进行抽象,交由子类去实现。

    而接口是对行为的抽象,表达的是 like a 的关系。比如:Bote-Royce like a Aircraft(像飞行器一样可以飞),但其本质上 is a Car。接口的核心是定义行为,即实现类可以做什么,至于实现类主体是谁、是如何实现的,接口并不关心。

    4. 接口与抽象类的使用场景

    熟悉Java的学生可能会质疑,通过重新提取CARE,可以实现上述接口的使用:

    1 /**
    2  * 会飞的汽车
    3  */
    4 abstract class FlyCar extends Car {
    5 
    6     //定义抽象方法
    7     public abstract void fly();
    8 }

    普通的汽车依然 extends Car,可以飞行的汽车 extends FlyCar 即可:

     1 /*
     2  * 继承 FlyCar,表示是可以飞行的汽车
     3  */
     4 class BoteRoyce extends FlyCar {
     5 
     6     /**
     7      * 覆写抽象方法,实现飞行能力
     8      */
     9     @Override
    10     public void fly() {
    11         System.out.println("假装会飞~");
    12     }
    13 }

    如果你也这么想,表示你 get 到了抽象类的点。不过话说回来,这样的话接口岂不是没有存在的意义了?

    当然不是了。就 BoteRoyce 而言,如果你关心的是“飞行汽车”这个整体,那么定义抽象类 FlyCar 是个不错的选择;如果你关心的是汽车具备“飞行”的行为,那不妨继续沿用前面使用 Aircraft 接口的方案。

    这与设计模式中的六条原则之一——RichterReplac.Principle——相一致,该原则规定对基类(抽象类或接口)的所有引用在使用其子类的对象时必须是透明的。也就是说,当您遵循这个原则时,您必须考虑您是关心“飞车”实体还是“飞车”行为,并将其作为基类来确定程序的可接受的子类对象。

    同时,“接口隔离原则”指导我们,一个类对另一个类的依赖应该建立在最小的接口上。相比于抽象类 FlyCar,接口 Aircraft 能最大限度的减少对外暴露的接口,并隐藏细节,更符合这一原则。

    因此,面向对象只是指导我们的编程,而不是规则和规则的想法。在实际的开发中,抽象类或接口的使用并非绝对受限,而是取决于您的业务场景和体系结构设计。

    5. 最后

    好了,这就是接口和抽象类的总结。你彻底理解了吗?

  • 相关阅读:
    年度最佳负能量的50句话
    drbd初探及Heartbeat+DRBD+MySQL
    slatsatck file模块2种写法及系统初始化
    补鞋匠---Cobbler 服务器自动搭建
    sudo日志记录记录(rsyslog)
    [svc]lnmp一键安装脚本(含有np与mysql分离)
    webBench&ad网站并发测试工具
    Amoeba软件实现mysql读写分离
    awstat分析nginx日志
    网站的PV UV IP---网站常见软件性能
  • 原文地址:https://www.cnblogs.com/aishangJava/p/10098052.html
Copyright © 2011-2022 走看看