通過女朋友來通俗易懂講解「介面回撥」,一不小心就被綠

2020-09-28 11:01:17

背景

最近要接一個資料,小松不知道怎麼弄,導師說:你可以定義一個介面回撥啊

然後我就吭哧吭哧的寫,寫到一半,發現有點不對勁。頓時發現自己的介面回撥用少了,只能對付常用的幾個場景,。但是一旦在幾百萬程式碼的產品中,很多介面回撥都是自定義或者用別人的自定義的。

所以今天,我們就好好的來剖析一下什麼是介面回撥

回撥

假設,現在小松有一個女朋友,小鹿,我們在一起生活,要生活呢就要洗碗,如果我和她都學會洗碗,顯然,我們內部的程式碼是重複的,我們都有一個洗碗的方法,這樣組成的家庭不好,理論上,只要有一個人會洗碗就夠了,另一個人去學別的東西。

現在小鹿會洗碗了,所以她的方法是這樣子

class littleLu {
    public void washUp(n){
        System.out.println("小鹿洗好了碗");
    }
}

小松作為一個居家好男人,也不老是讓小鹿洗碗啊,但是自己不能去學習洗碗,不然程式碼就重複了,所以聰明的小松寫了一個辦法,就是——「執子之手,用來洗碗」
小松讓小鹿改變她的方法,只要把小松傳進去,小鹿就會用小松的手來洗碗

abstract class Person{
    private String name;
    private String hand;
    public String getHand() {
        return hand;
    }
}
class LittleLu extends Person{
    private String name="littleLu";
    private String hand="littleLu的手";
    public void washUp(Person person){
        System.out.println(person.getHand()+"洗好了碗");
    }
}

上面的程式碼,首先定義一個人的抽象類,只要是人,都有名字還有手,再補一個獲得手的public方法,然後小鹿有一個洗碗的方法washUp,只要把人傳進去,就可以讓這個人的手來洗碗

怎麼做呢?小松將自己當做引數交給小鹿,然後小鹿用她的洗碗方法來洗就可以了(感覺有點奇怪,但是就是這個意思)

abstract class Person{...}
class LittleLu extends Person{...}
public class LittleSong extends Person{
    private String name="littleSong";
    private String hand="littleSong的手";

    public String getHand() {
        return hand;
    }

    public static void main(String[] args) {
        LittleLu littleLu=new LittleLu();
        LittleSong littleSong = new LittleSong();
        littleLu.washUp(littleSong);
    }
}

上面的main方法中,小松把自己傳入到小鹿的washUp方法裡面,小松不需要會洗碗,也能通過小鹿的方法來洗。
列印結果

littleSong的手洗好了碗

此時,回撥已經產生了

  1. 注意看,在LittleSong這個類的main方法中,new了一個littleLu,並且呼叫了littleLu的washUp方法,這個是一個呼叫。
  2. 但是,他在呼叫的同時也傳入了自己,使得washUp方法也可以拿到LittleSong物件,然後呼叫LittleSong中的getHand()方法將碗給洗了,如果這個步驟單獨看,他也是一個呼叫。

第一個步驟小松呼叫了小鹿的方法,第二個步驟小鹿又反過來呼叫小松的方法

核心句子是這句:如果不好理解可以再看看上文的例子
A呼叫B的方法,傳入自己,然後B的方法拿到A後再呼叫A的方法幹事情

這,就是回撥

回撥的最大好處在於,雖然最終做事情的是A,但是中途A需要某些東西,只有B有,就像例子中的雖然需要小松來洗碗,但是小松不會,此時需要小鹿的方法來幫助小松洗碗。

你可能會問,為什麼這麼麻煩?小松小鹿都學會洗碗不就好了嗎?
但是,此時只有兩個人,假如說,小鹿又找了一個男朋友,那這個男朋友是不是也要學會洗碗呢?如果小鹿有一群男朋友,外加包養幾個小鮮肉,豈不是每個人都要學會洗碗?
所以,有些方法,只能某個類有,雖然真正幹事情的是A,但是他不需要會幹事情,只要提供自己的東西給會幹事情的人幹即可

比如工人不需要會蓋房子,只要把自己的力氣賣給包工頭就行,然後包工頭反過來呼叫他們的力氣去蓋房子

介面

講到這裡可能有些人要噴我了,不是說好的介面回撥嗎?介面呢?
這是一個循序漸進的過程,為什麼需要介面?因為上面的方法雖然好,但是有很大的安全隱患!!看main方法

public static void main(String[] args) {
        LittleLu littleLu=new LittleLu();
        LittleSong littleSong = new LittleSong();
        littleLu.washUp(littleSong);
}

小松只是為了洗個碗,卻把自己整個交給了小鹿,小鹿豈不是可以對小松為所欲為?計算機中,給的許可權剛好足以,決不能多給,這是非常危險的,比如說littleSong的name就可以比littleLu獲取到。

此時介面就上場了,一個介面,只需要宣告一個getHand方法,然後傳入到小鹿的washUp方法中的引數,修改為這個介面即可,我們來看看,我們之前都是繼承Person的,現在,將Person變成介面,只保留getHand方法

interface Person{
     String getHand();
}
class LittleLu implements Person{
    private String name="littleLu";
    private String hand="littleLu的手";
    public void washUp(Person person){
        System.out.println(person.getHand()+"洗好了碗");
    }
    @Override
    public String getHand() {
        return hand;
    }
}
public class LittleSong implements Person{
    private String name="littleSong";
    private String hand="littleSong的手";

    @Override
    public String getHand() {
        return hand;
    }
    public static void main(String[] args) {
        LittleLu littleLu=new LittleLu();
        LittleSong littleSong = new LittleSong();
        littleLu.washUp(littleSong);
    }
}

此時的列印結果依然還是原來的,但是看到了嗎?在washUp方法中,傳入的是Person,而Person裡面,只有一個getHand方法,小鹿只能獲得getHand方法,也就是說,就算是阿貓阿狗,只要你實現了Person介面,有了getHand的方法,小鹿也會,並且只會用你的手來洗碗。

這就是介面回撥的核心要義,
你呼叫我的方法,然後把你傳進去,我的方法在那你呼叫你的方法幹事情
你為了保護自己,僅僅把你實現的介面部分傳進去,我也只看介面部分的東西

女朋友也是程式設計師,希望她不要看到這篇文章