(四) 抽象 与 接口

抽象与接口

1. 抽象

在第一周就有一个Shape类的例子。这个类有很多的子类,每个子类也都实现了父类的方法。实际上父类Shape只是一个抽象的概念而并没有实际的意义。如果请你画一个圆,你知道该怎么画;如果请你画一个矩形,你也知道该怎么画。但是如果我说:“请画一个形状,句号”。你该怎么画?同样,我们可以定义Circle类和Rectangle类的draw(),但是Shape类的draw()呢?

Shape类表达的是一种概念,一种共同属性的抽象集合,我们并不希望任何Shape类的对象会被创建出来。那么,我们就应该把这个Shape类定义为抽象的。我们用abstract关键字来定义抽象类。抽象类的作用仅仅是表达接口,而不是具体的实现细节。抽象类中可以存在抽象方法。抽象方法也是使用abstract关键字来修饰。抽象的方法是不完全的,它只是一个方法签名而完全没有方法体。

如果一个类有了一个抽象的方法,这个类就必须声明为抽象类。如果父类是抽象类,那么子类必须覆盖所有在父类中的抽象方法,否则子类也成为一个抽象类。一个抽象类可以没有任何抽象方法,所有的方法都有方法体,但是整个类是抽象的。设计这样的抽象类主要是为了防止制造它的对象出来。

抽象类的特点:

  • 抽象类和抽象方法必须用abstract关键字: abstract class Animal { }
  • 抽象方法不能有方法体: public abstract void eat(); (区分 空方法体 和 没有方法体)
  • 抽象类中不一定有抽象方法,但是有抽象方法的类必须定义为抽象类
  • 抽象类不能实例化(因为他不是具体的),但是支持具体子类的多态(向上转型)
  • 抽象类有构造方法,但是不能实例化,构造方法的作用是:用于子类访问父类数据的初始化
  • 抽象类的子类:
    • 如果不想重写所有抽象方法,这时候子类仍是抽象类
    • 重写所有的抽象方法,子类是一个具体的类

抽象类的成员的特点:

  • 成员变量:既可以是变量,也可以是常量

  • 构造方法:有,但作用是用于子类访问父类的数据的初始化

  • 成员方法:

    • 既可以是抽象的,也可以是非抽象的

    • 抽象方法,强制要求子类做的事情(必须被子类重写)

    • 非抽象方法,子类继承的事情,提高代码的复用性

  • abstract 不能和 finalprivatestatic 共存

  • 抽象类不能制造对象

  • 但是可以定义变量

    • 任何继承了抽象类的非抽象类的对象,可以赋给这个变量
    • 即任何子类的对象,都可以由一个抽象父类的引用变量来引用
  • 继承自抽象类的子类,必须覆盖/实现父类中的所有抽象函数(否则成为抽象类,不能制造对象)

  • 抽象 有两种概念:
    • 与具体相对:表示一种概念而非实体
    • 与细节相对:表示一定程度上而忽略细节着眼大局

2. 数据与表现分离

  • 程序的业务逻辑与表现无关
    • 表现可以是图形的,也可以是文本的
    • 表现可以是本地的也可以是远程的
  • View 和 Filed 的关系
    • 表现与数据的关系
    • View只管根据Field画出图形
    • Field只管数据的存放
    • 一旦数据更新以后,通知View重新画出整个图形
      • 不用去精心设计哪个局部需要更新
      • 简化了程序逻辑
  • 责任驱动的设计:

    • 将程序要实现的功能,分配到合适的类/对象中,是设计中非常重要的一环

      (什么类 做什么事情)

  • 遵循: 可拓展性原则,分离逻辑层和数据层,即分离数据和表现

3. 接口 (可拓展性 用于功能拓展)

类中的额外的功能可以通过实现接口来实现 implement interface

联想 驯兽师 锻炼出 部分猫狗的特殊能力

接口的特点:

  • 接口的定义:interface 接口名 { } (没有class)
  • 接口的实现: class 类名 implements 接口名 { }
  • 接口是一种特殊的抽象类,不能被实例化(多态向上造型)
  • 接口的子类:具体类实现接口:必须覆盖接口的所有方法
  • 经常在接口的实现类 会加上后缀 -Impl

接口的成员特点 (区别抽象类)

  • 成员变量:默认为静态常量 public static final (建议自己手动给出)

  • 构造方法:接口没有构造方法

  • 成员方法:接口方法不能带有主体(全都是抽象方法)(jdk1.8可以有普通方法)

    ​ 默认修饰符 public abstract

  • 接口规定了长什么样,但不管里面有什么

    • 接口的实现使用implements
  • 类的继承用extends, 接口的实现用implements

  • 一个类可以实现很多接口

  • 接口可以继承接口,但不能继承类

  • 一个类可以同时继承父类并且实现接口

  • 接口不能实现接口

类与接口关系

  • 类与类:继承关系,只能单继承
  • 类与接口:实现关系,可以单实现,也可以多实现
  • 接口与接口:继承关系,可以单继承,也可以多继承

抽象类 与 接口 区别:

  1. 成员区别:(成员变量,构造方法,成员方法)
  2. 关系区别:如上所述,继承与实现
  3. 设计理念的区别:
    • 抽象类:继承体现的是 “is a” 的关系,共性功能
    • 接口:接口被实现体现的是 “like a” /“tend to” 的关系, 拓展功能 (USB)

比如 猫狗案例: 加入跳高的额外功能

猫狗共性,抽取出父类(抽象类)Animal;(名字,年龄,吃饭,睡觉)

跳高的功能是一个新的拓展功能,所以我们定义一个接口:

接口:跳高 interface Jumping() { public abstract jump(); }

部分猫extends Cat implements Jumping { }:实现跳高;

部分狗extends Dog implements Jumping { }:实现跳高;

面向接口的编程方式

  • 两个东西之间的连接
  • 当你需要别人为你提供服务,或者需要别的东西的时候,你不是先定义一个类,而是先定义一个接口
  • 所有想要放到filed中的都是Cell
  • 设计程序时,先定义接口,再实现类
  • 任何需要在函数间传入传出的一定是接口,而不是具体的类
  • 是Java成功的关键之一,因为极其适合多人同时写一个大程序
    • 每个人只要提出要求,只需要提出一个接口,每个人根据这个接口去实现
    • 接口分隔开每个程序的不同部
  • 也是Java被批评的要点之一,因为代码量膨胀起来很快
  • 分析:从具体到抽象
  • 实现:从抽象到具体
  • 使用:具体
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容