相關閱讀:java
JAVA編程思想(一)經過依賴注入增長擴展性
JAVA編程思想(三)去掉彆扭的if,自注冊策略模式優雅知足開閉原則
JAVA編程思想(四)Builder模式經典範式以及和工廠模式如何選?
JAVA基礎(三)ClassLoader實現熱加載
Java併發編程入門(十一)限流場景和Spring限流器實現
HikariPool源碼(二)設計思想借鑑
人在職場(一)IT大廠生存法則數據庫
接口對調用者封裝了實現細節,調用者只需按接口規範使用,而不關心怎麼實現,例如咱們最多見的數據庫鏈接接口Connection,當經過某個工具包獲取Connection後(如HikariPool或者阿里Druid),調用者並不關心實際獲取到的是廠家提供的驅動類,仍是被工具包封裝以後的代理類。編程
有接口就意味着有變化點,若是沒有變化點,也就不須要定義接口,按照固定邏輯實現便可,照此反推,即-有可能發生變化的邏輯,才適合定義接口。例如Java的集合框架,List,Map,Set都有不少不一樣實現類,不一樣的實現類即是不一樣的變化點,能夠知足不一樣的須要。併發
接口是一套標準,例如插座,手機充電口,插入插座的部分並無什麼不一樣(注意:這裏僅說的是插入的部分),從這個角度看接口就是一個標準,只要符合標準就能適配接口,所以並非必定要有變化點才能定義接口,標準的接口是爲了更加規範,通用。框架
綜上,就是接口的本質,透過這些本質,就很容易知道何時須要定義接口。ide
從接口的本質實際已經能夠看出面向接口編程的優勢:工具
A. 接口穩定,易於擴展
B. 替換接口實現時,修改代價小
C. 代碼規範,易於維護post
關於接口編程如何易於擴展,請參考:JAVA編程思想(一)經過依賴注入增長擴展性。ui
通常狀況下有兩種方式:spa
提供者提供的方法入參或構造器入參定義爲接口,由調用者自行肯定實現類,此時調用者要關心接口實現,並可能自行提供最佳實現。
提供者提供的方法中經過工廠類生成接口實例,調用者使用該接口實例,不關心具體實現,例如數據庫鏈接類Connection,一般都是經過工廠類生成給調用者使用。
以上兩種調用方式也決定了具體的實現方式。
在接口的本質中已經提到,當要對外屏蔽實現,功能有變化點,或制訂標準時須要定義接口,前兩個的的例子很常見,就再也不舉例,這裏僅舉例說明接口是如何用於制訂標準的。
注意:
- 本例目的僅爲說明接口可用於制訂標準,進而可採用相同的模式來處理相似邏輯,這樣易於後續新開發和維護同類功能,本例並未完整實現。
- 另外爲了簡單,本例都寫成了內部類和接口。
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 {
}
複製代碼
- 首先透過接口的本質:是否對外提供接口屏蔽內部實現,是否有變化點,是否要制訂標準以方便維護,這三個方面來肯定是否須要定義接口。
- 通常來講要用接口是由於事物既具備共性又有不一樣點,要能找到共性又具備不一樣點才須要定義接口,例如飛機和鳥都能飛,這是共性,但飛的方式不一樣,這是不一樣點,這個尋找共性的過程就是抽象的過程,抽象能力高則面向接口編程能力就高。
- 接口不是必須的,當拿不定主意是否須要接口時一般有兩個可能:「確實不須要接口」 和 「當下你還無法肯定是否須要接口」,這時也沒必要勉強,等發現須要時再重構。
end.
<--閱過留痕,左邊點贊 !