設計模式(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」第一手更新,有興趣的朋友可以關注公眾號,第一時間看到筆者分享的各項知識點,謝謝!筆芯!