Bootstrap

设计模式(04):接口和抽象类

接口和抽象类

区别

接口是对行为的抽象,其重点关注的是要有该行为。


抽象类是对一些共性行为的聚合,将多个子类都有的具体行为抽象成一个方法,形成复用。

public abstract class Bird {
    private String name;
    private BigDecimal weight;
    private String habit;
}

public interface IFlyable {
    /**
     * a bird that can fly
     */
    void fly();
}

public class Sparrow extends Bird implements IFlyable {
    @Override
    public void fly() {
        Console.log("Sparrow can fly");
    }
}

举例来说,这里我们首先定义了一个 Bird 类,但是,我们却无法在其中定义 fly 方法,为什么呢?


因为并不是所有鸟都会飞的,如果是在 Bird 中定义的话,那么所有实现子类,都拥有这个行为,因此,我们考虑定义接口,来将其行为抽象成一种能力,只要有该能力的类都可以实现该类,这这里,你甚至可以定义飞机来实现 IFlyable。


而从语法特性来描述的话,有如下区别:

  • 接口不能有属性,而抽象类可以有属性和方法;
  • 接口中方法不能被实现(Java8 后可以有默认实现方法),抽象类中的方法可以有实现,也可以没有;

使用时机

从上面的例子中,也可以看出何时使用抽象类,何时使用接口,关键点是行为的是否可继承性。


此外,在 Java 要实现多继承的时候,也只能使用接口,因为 Java 不支持多继承。

存在意义

首先说抽象类。抽象类本质也是一个类,因此类的继承特性最首要的就是解决代码复用的问题。


通过继承,可以直接复用父类中的方法,并把需要子类来自定义实现的方法定义成 抽象方法,从而实现复用。


并且因为继承的关系,还可以使用面向对象中的 **多态 **特性,用抽象类的指针指向子类的对象。


如果说抽象类关注的是代码复用的话,接口更加关注的就是 **解耦。**通过接口定义来让第三方不要关注具体的实现,如果你要调用或是实现自己的方法的话,关注定义即可。


深入了解

通过,对接口和抽象类的了解,现在,我们来看一下,如何在不支持上述语法特性的语言中,实现接口和抽象类呢。

在这里,因为没有装 py 和 C++ 的环境,因此就用 Java 简单代替一下,所完成的逻辑和方法是 的。


用抽象类来实现接口的定义:

/**
 * @author iceWang
 * @date 2020/10/17
 * 用抽象类来模拟接口
 */
public abstract class AbstractToInterface {
    protected AbstractToInterface(){};

    /**
     * 类似于接口中的定义,子类必须要实现
     */
    public abstract void demo();
}


用普通类来实现抽象类的作用:

/**
 * @author iceWang
 * @date 2020/10/17
 * 用普通类来模拟抽象类
 */
public class ClassToAbstractClass {
    protected ClassToAbstractClass() {
    }

    /**
     * 类似于抽象类中的抽象方法的定义,因为要保证子类必须重写,因此直接抛出异常
     */
    public void abstractFunction() throws Exception {
        throw new Exception("Error DesignModel");
    }

    /**
     * 类似于抽象类中的普通方法的定义,子类不必一定重写
     */
    public void plainFunction() {
        System.out.println("Hello DesignModel");
    }
}


用普通类来实现接口的定义:

/**
 * @author iceWang
 * @date 2020/10/17
 * 用普通类来模拟接口
 */
public class ClassToInterface {
    protected ClassToInterface() {
    }

    /**
     * 类似于接口中的定义,因为要保证子类必须实现,因此直接抛出异常
     */
    public void demo() throws Exception {
        throw new Exception("111");
    }
}

接口的使用

接口的实现,可以让我们在编程时采用 面向接口编程 的思想,即只关注接口定义即可,不必过多关注具体的实现细节,从而实现两方的解耦。


而为了支持面向接口编程,需要在开发过程中:

  • 函数的命名不能暴露任何实现细节;
  • 具体的实现细节进行封装,不暴露给调用者;

公众号截图




文章在公众号「iceWang」第一手更新,有兴趣的朋友可以关注公众号,第一时间看到笔者分享的各项知识点,谢谢!笔芯!

;