JAVA編程思想(二)如何面向接口編程

Java極客  |  做者  /  鏗然一葉
這是Java極客的第 59 篇原創文章

相關閱讀:java

JAVA編程思想(一)經過依賴注入增長擴展性
JAVA編程思想(三)去掉彆扭的if,自注冊策略模式優雅知足開閉原則
JAVA編程思想(四)Builder模式經典範式以及和工廠模式如何選?
JAVA基礎(三)ClassLoader實現熱加載
Java併發編程入門(十一)限流場景和Spring限流器實現
HikariPool源碼(二)設計思想借鑑
人在職場(一)IT大廠生存法則數據庫

1. 接口的本質

接口封裝了細節

接口對調用者封裝了實現細節,調用者只需按接口規範使用,而不關心怎麼實現,例如咱們最多見的數據庫鏈接接口Connection,當經過某個工具包獲取Connection後(如HikariPool或者阿里Druid),調用者並不關心實際獲取到的是廠家提供的驅動類,仍是被工具包封裝以後的代理類。編程

有接口就意味着有變化點

有接口就意味着有變化點,若是沒有變化點,也就不須要定義接口,按照固定邏輯實現便可,照此反推,即-有可能發生變化的邏輯,才適合定義接口。例如Java的集合框架,List,Map,Set都有不少不一樣實現類,不一樣的實現類即是不一樣的變化點,能夠知足不一樣的須要。併發

接口是一套標準

接口是一套標準,例如插座,手機充電口,插入插座的部分並無什麼不一樣(注意:這裏僅說的是插入的部分),從這個角度看接口就是一個標準,只要符合標準就能適配接口,所以並非必定要有變化點才能定義接口,標準的接口是爲了更加規範,通用。框架

綜上,就是接口的本質,透過這些本質,就很容易知道何時須要定義接口。ide

2. 面向接口編程的優勢

從接口的本質實際已經能夠看出面向接口編程的優勢:工具

A. 接口穩定,易於擴展
B. 替換接口實現時,修改代價小
C. 代碼規範,易於維護post

關於接口編程如何易於擴展,請參考:JAVA編程思想(一)經過依賴注入增長擴展性ui

3. 接口調用方式

通常狀況下有兩種方式:spa

3.1 入參爲接口

提供者提供的方法入參或構造器入參定義爲接口,由調用者自行肯定實現類,此時調用者要關心接口實現,並可能自行提供最佳實現。

3.2 工廠類生成接口實例

提供者提供的方法中經過工廠類生成接口實例,調用者使用該接口實例,不關心具體實現,例如數據庫鏈接類Connection,一般都是經過工廠類生成給調用者使用。

以上兩種調用方式也決定了具體的實現方式。

4. 面向接口編程舉例

在接口的本質中已經提到,當要對外屏蔽實現,功能有變化點,或制訂標準時須要定義接口,前兩個的的例子很常見,就再也不舉例,這裏僅舉例說明接口是如何用於制訂標準的。

4.1. 經過接口制訂標準例子

注意:

  1. 本例目的僅爲說明接口可用於制訂標準,進而可採用相同的模式來處理相似邏輯,這樣易於後續新開發和維護同類功能,本例並未完整實現。
  2. 另外爲了簡單,本例都寫成了內部類和接口。
import java.util.List;

public class StandardDemo {
    
    public static void main(String[] args) {
        // 在這種場景下,實際使用時必定會引用到實現類,並無屏蔽實現細節,此處接口的做用就是統一標準方法,方便維護。
        DAOInterface<Person, PrimaryKey> dao = new PersonDAO<>();
        
        // 如下代碼並無完整實現,僅僅用於示例這個標準接口是如何使用的
        List<Person> people = dao.query(new Condition());
        Person person = dao.queryByPrimaryKey(new PrimaryKey());
        dao.update(new Person());
    }
    
}

// 這個接口的主要目的是:定義一套標準接口方法,要求全部數據庫訪問都遵循這些標準接口方法來實現,使得統一模式以後更易於維護,而不是各個開發人員各寫一套出來。
interface DAOInterface<T, K> {
    List<T> query(Condition condition);
    
    T queryByPrimaryKey(K entiryKey);
    
    int update(T entity);
    
    int create(T entity);
}

class PersonDAO<Person, PrimaryKey> implements DAOInterface<Person, PrimaryKey> {
    @Override
    public List<Person> query(Condition condition) {
        return null; // 僅示例,沒有完整實現
    }
    
    @Override
    public Person queryByPrimaryKey(PrimaryKey primaryKey) {
        return null; // 僅示例,沒有完整實現
    }
    
    @Override
    public int update(Person entity) {
        return 0; // 僅示例,沒有完整實現
    }
    
    @Override
    public int create(Person entity) {
        return 0; // 僅示例,沒有完整實現
    }
}

class StudentDAO<Student, PrimaryKey> implements DAOInterface<Student, PrimaryKey> {
    @Override
    public List<Student> query(Condition condition) {
        return null; // 僅示例,沒有完整實現
    }
    
    @Override
    public Student queryByPrimaryKey(PrimaryKey primaryKey) {
        return null; // 僅示例,沒有完整實現
    }
    
    @Override
    public int update(Student student) {
        return 0; // 僅示例,沒有完整實現
    }
    
    @Override
    public int create(Student student) {
        return 0; // 僅示例,沒有完整實現
    }
}

// 僅示例,沒有完整實現
class Student {
}

// 僅示例,沒有完整實現
class Person {
}

// 查詢條件類,並未實現
class Condition {
}

// 主鍵類,並未實現
class PrimaryKey {
}
複製代碼

5. 總結:如何面向接口編程

  1. 首先透過接口的本質:是否對外提供接口屏蔽內部實現,是否有變化點,是否要制訂標準以方便維護,這三個方面來肯定是否須要定義接口。
  2. 通常來講要用接口是由於事物既具備共性又有不一樣點,要能找到共性又具備不一樣點才須要定義接口,例如飛機和鳥都能飛,這是共性,但飛的方式不一樣,這是不一樣點,這個尋找共性的過程就是抽象的過程,抽象能力高則面向接口編程能力就高。
  3. 接口不是必須的,當拿不定主意是否須要接口時一般有兩個可能:「確實不須要接口」「當下你還無法肯定是否須要接口」,這時也沒必要勉強,等發現須要時再重構。

end.


<--閱過留痕,左邊點贊 !

相關文章
相關標籤/搜索