java回調方法、鈎子方法以及模板方法模式


在面向對象的語言中,回調則是通過接口或抽象類來實現的,我們把實現這種接口的類稱為回調類,回調類的對象稱為回調對象,其處理事件的方法叫做回調方法。(摘自百度百科)

那么通過上面那句話將百度百科中的“回調函數”翻譯成JAVA版:回調方法就是一個通過回調對象的引用(java中的引用存的是對象的地址)調用的方法。如果你把

回調對象的引用(地址)作參數傳遞給另一個方法,當這個引用被用來調用其所指向的方法時,我們就說這是回調方法。回調方法不是由該方法的實現方直接調用,
而是在特定的事件或條件發生時由另外的一方調用的,用於對該事件或條件進行響應。

 

      下面我們來通過一個小需求來實現回調,需求為:王鋼蛋去餐廳打飯,餐廳服務員根據其飯量為其打飯。我們先構思下,首先要有個接口,接口中定義個抽象方法為 飯量(回調接口);其次創建王鋼蛋(回調類),讓王鋼蛋實現這個接口,並想好其飯量(回調方法);最后創建餐廳,餐廳服務員(另一方)接待王鋼蛋(回調對 象)並根據其提供的飯量(回調方法)打飯(特定事件,該事件會調用回調方法)。上代碼:

 

/**
 * 顧客,去食堂吃飯有個前提,要告訴服務員其飯量,才會給你盛飯
 * @author coder
 *
 */
interface Client{
    /**
     * 告訴服務員其飯量
     * @return 
     */
    public String appetite();
}

class WangGangDan implements Client{
    @Override
    public String appetite() {
        return "一車米飯";
    }
}
/**
*食堂
*/
class Restaurant{
    /**
     * 打飯方法,前提是客戶要告知服務員你的飯量,他會根據你的飯量給你“盛”飯
     * @param client 排隊的客戶
     * @return
     */
    public String dozenRice(Client client){
        return "盛了"+client.appetite();
    }

}

public class Test1 { //業務處理類,老王去打飯
    public static void main(String[] args) {
        WangGangDan laowang=new WangGangDan(); //王鋼蛋以別名laowang去食堂要飯
        Restaurant waiter=new Restaurant(); 
        String dozenRice=waiter.dozenRice(laowang);
        System.out.println(dozenRice); //最后老王“盛了一車米飯”
        //但是通常我們打飯時不會告訴服務員我們叫什么,這樣太麻煩了,那么可不可以只告訴服務員
        //飯量多少就給我們打飯呢?按常理來說我們去餐廳也只會要一次飯。
        //匿名內部類多用來實現回調,簡便
        String dozenRice1=waiter.dozenRice(new Client(){ 
            @Override
            public String appetite() {
                return "一鍋米飯";
            }});
        System.out.println(dozenRice1); 
    }
}

         這里將利用模板方法模式來說明鈎子方法是什么,許多設計模式都用到了回調,鈎子之類的概念,這些基礎點理解了,有些模式也就不那么晦澀難懂了,稍微改寫下上面的代碼就可以:

/**
 *  模板方法模式:在一個方法中定義一個算法的骨架,而將一些步
 *  驟延遲到子類中。模板方法使得子類可以在不改變算法結構的情
 *  況下,重新定義算法中的某些步驟。
 * 【鈎子方法】:原理就是實現為空的方法,在某任務之前、之后、
 *  執行中、報異常后調用的方法(是不是有種熟悉的感覺)。
 *  通常鈎子方法是通過抽象類或是本類中的空方法來實現的。
 *
 */
 abstract class Client{
    /**
     * 【模板方法】
     */
    public void templateMethod(){
        before();
        appetite();
        after();
    }
    /**
     * 【鈎子方法】在盛飯前(一個空的實現)
     */
     protected void before(){};
    /**
     * 【抽象方法】告訴服務員其飯量
     * @return 飯量
     */
    public abstract void appetite();
    /**
     * 【具體方法】盛飯后
     */
    private void after(){
        //實際項目這里是共有的業務邏輯
        System.out.println("拿筷子,找桌子,開吃...");
    }
}
/**
 *食堂
 */
class Restaurant{
    /**
     * 打飯方法,前提是客戶要告知服務員你的飯量,他會根據你的飯量給你“盛”飯
     * @param client 排隊的客戶
     * @return
     */
    public void dozenRice(Client client){
        client.templateMethod();
    }
}
public class Test1 { //業務處理類,老王去打飯
    public static void main(String[] args) {
        Restaurant waiter=new Restaurant();
        waiter.dozenRice(new Client(){
            @Override
            protected void before() {
                System.out.println("對服務員吹胡子瞪眼!!");
            }
            @Override
            public void appetite() {
                System.out.println("盛了一鍋米飯");
            }});
    }
}

 

 

 

 

 

    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM