1. 程式人生 > >java模組之間的呼叫(介面的回撥)

java模組之間的呼叫(介面的回撥)

模組間呼叫

在一個應用系統中,無論使用何種語言開發,必然存在模組之間的呼叫,呼叫的方式分為幾種:

(1)同步呼叫

同步呼叫是最基本並且最簡單的一種呼叫方式,類A的方法a()呼叫類B的方法b(),一直等待b()方法執行完畢,a()方法繼續往下走。這種呼叫方式適用於方法b()執行時間不長的情況,因為b()方法執行時間一長或者直接阻塞的話,a()方法的餘下程式碼是無法執行下去的,這樣會造成整個流程的阻塞。

(2)非同步呼叫

非同步呼叫是為了解決同步呼叫可能出現阻塞,導致整個流程卡住而產生的一種呼叫方式。類A的方法方法a()通過新起執行緒的方式呼叫類B的方法b(),程式碼接著直接往下執行,這樣無論方法b()執行時間多久,都不會阻塞住方法a()的執行。但是這種方式,由於方法a()不等待方法b()的執行完成,在方法a()需要方法b()執行結果的情況下(視具體業務而定,有些業務比如啟非同步執行緒發個微信通知、重新整理一個快取這種就沒必要),必須通過一定的方式對方法b()的執行結果進行監聽。在Java中,可以使用Future+Callable的方式做到這一點,具體做法可以參見我的這篇文章

Java多執行緒21:多執行緒下其他元件之CyclicBarrier、Callable、Future和FutureTask

(3)回撥

 

最後是回撥,回撥的思想是:

  • 類A的a()方法呼叫類B的b()方法
  • 類B的b()方法執行完畢主動呼叫類A的callback()方法

這樣一種呼叫方式組成了上圖,也就是一種雙向的呼叫方式。

程式碼示例

接下來看一下回調的程式碼示例,程式碼模擬的是這樣一種場景:老師問學生問題,學生思考完畢回答老師。

首先定義一個回撥介面,只有一個方法tellAnswer(int answer),即學生思考完畢告訴老師答案:

複製程式碼
1 /**
2  * 回撥介面,原文出處http://www.cnblogs.com/xrq730/p/6424471.html
3 */ 4 public interface Callback { 5 6 public void tellAnswer(int answer); 7 8 }
複製程式碼

定義一個老師物件,實現Callback介面:

複製程式碼
 1 /**
 2  * 老師物件,原文出處http://www.cnblogs.com/xrq730/p/6424471.html
 3  */
 4 public class Teacher implements Callback {
 5 
 6     private Student student;
 7     
 8     public Teacher(Student student) {
9 this.student = student; 10 } 11 12 public void askQuestion() { 13 student.resolveQuestion(this); 14 } 15 16 @Override 17 public void tellAnswer(int answer) { 18 System.out.println("知道了,你的答案是" + answer); 19 } 20 21 }
複製程式碼

老師物件有兩個public方法:

(1)回撥介面tellAnswer(int answer),即學生回答完畢問題之後,老師要做的事情

(2)問問題方法askQuestion(),即向學生問問題

接著定義一個學生介面,學生當然是解決問題,但是接收一個Callback引數,這樣學生就知道解決完畢問題向誰報告:

複製程式碼
1 /**
2  * 學生介面,原文出處http://www.cnblogs.com/xrq730/p/6424471.html
3  */
4 public interface Student {
5     
6     public void resolveQuestion(Callback callback);
7     
8 }
複製程式碼

最後定義一個具體的學生叫Ricky:

複製程式碼
 1 /**
 2  * 一個名叫Ricky的同學解決老師提出的問題,原文出處http://www.cnblogs.com/xrq730/p/6424471.html
 3  */
 4 public class Ricky implements Student {
 5 
 6     @Override
 7     public void resolveQuestion(Callback callback) {
 8         // 模擬解決問題
 9         try {
10             Thread.sleep(3000);
11         } catch (InterruptedException e) {
12             
13         }
14         
15         // 回撥,告訴老師作業寫了多久
16         callback.tellAnswer(3);
17     }
18 
19 }
複製程式碼

在解決完畢問題之後,第16行向老師報告答案。

寫一個測試類,比較簡單:

複製程式碼
 1 /**
 2  * 回撥測試,原文出處http://www.cnblogs.com/xrq730/p/6424471.html
 3  */
 4 public class CallbackTest {
 5 
 6     @Test
 7     public void testCallback() {
 8         Student student = new Ricky();
 9         Teacher teacher = new Teacher(student);
10         
11         teacher.askQuestion();
12         
13     }
14     
15 }
複製程式碼

程式碼執行結果就一行:

知道了,你的答案是3

簡單總結、分析一下這個例子就是:

(1)老師呼叫學生介面的方法resolveQuestion,向學生提問

(2)學生解決完畢問題之後呼叫老師的回撥方法tellAnswer

這樣一套流程,構成了一種雙向呼叫的關係。

程式碼分析

分析一下上面的程式碼,上面的程式碼我這裡做了兩層的抽象:

(1)將老師進行抽象

  • 將老師進行抽象之後,對於學生來說,就不需要關心到底是哪位老師詢問我問題,只要我根據詢問的問題,得出答案,然後告訴提問的老師就可以了,即使老師換了一茬又一茬,對我學生而言都是沒有任何影響的

(2)將學生進行抽象

  • 將學生進行抽象之後,對於老師這邊來說就非常靈活,因為老師未必對一個學生進行提問,可能同時對Ricky、Jack、Lucy三個學生進行提問,這樣就可以將成員變數Student改為List<Student>,這樣在提問的時候遍歷Student列表進行提問,然後得到每個學生的回答即可

這個例子是一個典型的體現介面作用的例子,之所以這麼說是因為我想到有些朋友可能不太明白介面的好處,不太明白介面好處的朋友可以重點看一下這個例子,多多理解。

總結起來,回撥的核心就是回撥方將本身即this傳遞給呼叫方,這樣呼叫方就可以在呼叫完畢之後告訴回撥方它想要知道的資訊。回撥是一種思想、是一種機制,至於具體如何實現,如何通過程式碼將回調實現得優雅、實現得可擴充套件性比較高,一看開發者的個人水平,二看開發者對業務的理解程度。

同步回撥與非同步回撥

上面的例子,可能有人會提出這樣的疑問:

這個例子需要用什麼回撥啊,使用同步呼叫的方式,學生物件回答完畢問題之後直接把回答的答案返回給老師物件不就好了?

這個問題的提出沒有任何問題,可以從兩個角度去理解這個問題。

首先,老師不僅僅想要得到學生的答案怎麼辦?可能這個老師是個更喜歡聽學生解題思路的老師,在得到學生的答案之前,老師更想先知道學生姓名和學生的解題思路,當然有些人可以說,那我可以定義一個物件,裡面加上學生的姓名和解題思路不就好了。這個說法在我看來有兩個問題:

(1)如果老師想要的資料越來越多,那麼返回的物件得越來越大,而使用回撥則可以進行資料分離,將一批資料放在回撥方法中進行處理,至於哪些資料依具體業務而定,如果需要增加返回引數,直接在回撥方法中增加即可

(2)無法解決老師希望得到學生姓名、學生解題思路先於學生回答的答案的問題

因此我認為簡單的返回某個結果確實沒有必要使用回撥而可以直接使用同步呼叫,但是如果有多種資料需要處理且資料有主次之分,使用回撥會是一種更加合適的選擇,優先處理的資料放在回撥方法中先處理掉。

另外一個理解的角度則更加重要,就是標題說的同步回撥和非同步回撥了。例子是一個同步回撥的例子,意思是老師向Ricky問問題,Ricky給出答案,老師問下一個同學,得到答案之後繼續問下一個同學,這是一種正常的場景,但是如果我把場景改一下:

老師並不想One-By-One這樣提問,而是同時向Ricky、Mike、Lucy、Bruce、Kate五位同學提問,讓同學們自己思考,哪位同學思考好了就直接告訴老師答案即可。

這種場景相當於是說,同學思考完畢完畢問題要有一個辦法告訴老師,有兩個解決方案:

(1)使用Future+Callable的方式,等待非同步執行緒執行結果,這相當於就是同步呼叫的一種變種,因為其本質還是方法返回一個結果,即學生的回答

(2)使用非同步回撥,同學回答完畢問題,呼叫回撥介面方法告訴老師答案即可。由於老師物件被抽象成了Callback介面,因此這種做法的擴充套件性非常好,就像之前說的,即使老師換了換了一茬又一茬,對於同學來說,只關心的是呼叫Callback介面回傳必要的資訊即可

相關推薦

url獲取資料介面呼叫方法+自定義顯示介面

呼叫方法 new MyTask(new MyTask.Icallbacks(){});//生成返回值myTask.execute("地址");//介面設定 public class MyNetTask

RecyView+條目點選介面

1,佈局檔案 <android.support.v7.widget.RecyclerView android:id="@+id/recy" android:layout_width="match_parent" android:layout_height="

C# 委託的三種呼叫示例同步呼叫、非同步呼叫、非同步

首先,通過程式碼定義一個委託和下面三個示例將要呼叫的方法: 程式碼如下: public delegate int AddHandler(int a,int b); public class 加法類 { public static int A

APP微信支付java後臺_統一下單和

微信支付Java後臺1.微信配置資訊 global.properties2.方法wxpay用於生成預支付訂單資訊        方法notifyWeiXinPay用於微信支付成功後的回撥, 注意: 在手機端使用微信支付成功後,微信伺服器會根據提供的回撥地址進行回撥, para

Fragment靜態傳值RecyclerView,介面

public class Fragmnet1 extends Fragment { private RecyclerView rec; public void setOnItem(OnItem onItem) { this.onItem = onItem; }

python中的Redis鍵空間通知過期

介紹 Redis是一個記憶體資料結構儲存庫,用於快取,高速資料攝取,處理訊息佇列,分散式鎖定等等。 使用Redis優於其他記憶體儲存的優點是Redis提供永續性和資料結構,如列表,集合,有序集和雜湊。 在本文中,我想簡要介紹一下Redis鍵空間通知。我將解釋鍵空間通知是什麼,並演示如何配置Redis以接

promise實現公共彈框元件非同步

情景再現:        1、使用者點選按鈕,彈出確認窗體        2、使用者確認和取消有不同的處理解決方案:         1、採用ES6的promise語法,實現非同步回撥(jquery3.0以後支援)        2、案例樣式採用bootstrap上程式碼:&

java模組之間呼叫介面

模組間呼叫在一個應用系統中,無論使用何種語言開發,必然存在模組之間的呼叫,呼叫的方式分為幾種:(1)同步呼叫同步呼叫是最基本並且最簡單的一種呼叫方式,類A的方法a()呼叫類B的方法b(),一直等待b()方法執行完畢,a()方法繼續往下走。這種呼叫方式適用於方法b()執行時間不長的情況,因為b()方法執行時間一

java呼叫dll時函式的實現jna

java呼叫dll檔案需要使用回撥函式作為公開函式的引數時,用以下方法實現: 首先,看c++中定義的dll公開函式: typedef void (*ccback)(char *name ,int le

Fragment3和其他Fragment之間互動--偉大的介面

這個是我一直想要找的,沒想到偉大的官網竟然有。感動到流鼻涕了。。 為了重用Fragment UI元件,我們應該建立一個完全獨立的自控的,定義自己佈局和行為的模型元件。一旦我們定義了這些可重用的Fragments,我們就可以把它們和Activity關聯起來並且用應用邏輯連線

Java向上,向下造型造型和介面中的問題

最近回顧了一下java繼承中的問題,下面貼程式碼: package com.cc; /** * 目的:問題驗證,關於向上和向下造型過程中,檢測存在繼承關係的物件訪問關係。 * * * @

26、【支付模組開發】——支付寶函式實現和查詢使用者訂單狀態介面編寫

####1、支付寶回撥函式實現 我們在除錯支付寶沙箱環境的時候,支護寶會有一個回撥函式,也就是在支付成功之後,可以呼叫我們支付之後需要執行的相關方法,從而達到資料庫的資料和我們的操作相統一。 首先我們先在本地將回調函式編寫好~ 在OrderController類中新建我們的支付寶回撥函式

Java中的單例模式、工廠模式、介面、異常

for迴圈:起點為基本資料型別,包括boolean . equals():重寫原因,希望在地址不同但內容相同時也能返回true。 匿名物件:直接new出物件,不需要物件名來接收。 new Person().show(); 內部類:類

介面,用最簡單的一個匿名內部類來講解介面高階應用場景,讓你對介面的瞭解登堂入室

介面回撥,是Java開發者必須要學的一個東西,可是他呢,書上沒有,大神部落格裡也沒有,所以導致了有部分小夥紙並不瞭解這個知識,所以這裡做一個最簡單的講解。 (先不牽扯什麼非同步回撥、同步回撥) 首先,只需要記住一點,介面回撥的含義就是把程式碼換個地方寫。 正常我們是這

AIDL實現不同應用之間跨程序通訊及傳遞與返回各種資料型別和遠端介面

含義:AIDL(Android Interface Definition Language),是android介面定義語言,這種語言定義了一個客戶端和伺服器通訊介面的一個標準、規範。 為什麼要有AIDL?  我們都知道android中的四大元件Activit

Android中Recyclerview使用7----條目中按鈕點選事件,在activity中呼叫(介面)

0引入Recyclerview的支援庫    compile 'com.android.support:recyclerview-v7:23.4.0' 1效果圖: 2程式碼: 2.1MainActivity中: <span style="font-size:18p

Java介面詳解

一.產生介面回撥的場景 在現實生活中,產生介面回撥的場景很簡單,比如我主動叫你幫我做一件事,然後你做完這件事之後會通知我,"通知我"這個動作就是介面回撥的動作.介面回撥重在理解思就好.再舉個例子用於下面的程式碼演示,老師讓學生做課堂練習,學生做完練習後並告訴老師. 二.什麼是介面回撥 在

crf++模型訓練到c++、java呼叫介面

crf模型是個特別好用的模型,做分詞、做ner等nlp工作都力離不開,訓練crf模型用很多工具,比較出名的就是今天要講的crf++,其文件清晰,支援各種語言的介面,本篇blog要講的是c++和java的介面,   這裡java的介面是通過jni呼叫c++實際本質還是c++,不

JAVA中的介面

  定義: /** * @author Administrator * @project: TestOne * @package: PACKAGE_NAME * @date: 2018/11/30 0030 15:42 * @brief: 郭寶 */ public

Java 介面傳值

--------------------------MainActivity------------------------public class MainActivity extends AppCo