把"重試"抽象出來做個工具類吧
背景介紹
我們在工作中難免會寫一些重複性的程式碼,所以需要我們具備一定的抽象能力,比如把共同的邏輯抽取到抽象類中,也可以通過一些工具類來避免冗餘程式碼
今天這篇文章就是把一個呼叫服務的重試功能抽取出一個工具類,以備複用。這裡為了方便介紹,把呼叫服務簡化成方法的呼叫,被呼叫的 foo 方法如下:
public static List<String> foo() {// 沒有顯示丟擲異常 System.out.println("呼叫方法"); // 模擬丟擲異常 System.out.println(1/0); List<String> list = new ArrayList<>(); list.add("1"); return list; }
呼叫方和重試邏輯如下:
List<String> result = null; // 重試次數 int retryCount = 0; // 呼叫服務的開關,預設開啟 boolean callSwitch = true; // 只要呼叫服務開關開著,並且重試次數不大於最大的重試次數,就呼叫服務 while (callSwitch && retryCount <= 3) { try { // 呼叫服務 result = foo(); // 省略了對結果的校驗,假設到了這裡就說明沒有問題,把呼叫服務開關關掉 callSwitch = false; } catch (Exception e) { // 發生了異常(比如超時,就需要重試了) // 呼叫服務的開關開啟 callSwitch = true; retryCount++; } } // 後面對 result 進行處理
其實上面的程式碼就已經解決了,服務重試的邏輯,測試沒有問題後,可以提交程式碼讓同事幫忙進行 CR 了,可是小朋同學看到這個程式碼後,給了建議:
可以抽象一層,提出一個 retry 的工具類,這樣大家都可以簡單複用你的 retry 邏輯
抽象思考過程
白牙心想,也對哈,那就提出一個工具類吧,可是發了會兒呆,竟然沒有頭緒(反映出了抽象能力的薄弱,平時要多注意抽象能力的培養)。小朋見狀,給了一點提示,白牙立馬在鍵盤上噼裡啪啦敲擊了起來,就有了下面的工具類
主要依賴函式式介面 Supplier 和 BiFunction
public class RetryUtil { public static <T> T retry(int maxRetryCount, Supplier<T> supplier, BiFunction<T, Exception, Boolean> consumer) { T result = null; Exception exception = null; int retryCount = 0; boolean callMethod = true; while (callMethod && retryCount <= maxRetryCount) { try { // 獲取呼叫服務的結果 result = supplier.get(); } catch (Exception e) { // 如果重試次數不小於最大重試次數,就丟擲異常,我們把對異常的處理交給業務方 if (retryCount >= maxRetryCount) { throw e; } exception = e; } // 對結果進行判斷 callMethod = consumer.apply(result, exception); if (callMethod) { retryCount++; } } return result; } }
業務呼叫方的程式碼如下:
List<String> result1 = retry(3,// 最大重試次數
()-> foo(),// 呼叫服務
(list, e) -> e != null || list == null || list.isEmpty());// 對結果處理
自測沒有問題後,又提交程式碼讓小朋給 CR 一下,小朋凝視了會兒,就有了下面的對話
小朋:“retry 方法沒有丟擲異常”
白牙:“被呼叫的服務沒有顯示的丟擲異常,這裡也就沒有丟擲”
小朋:“那人如果有服務方顯示丟擲異常呢?”
白牙:“我再改一版”
服務方顯示丟擲了異常,這樣 retry 方法也得顯示丟擲異常,但呼叫方就會顯示會處理的異常,如下所示:
public static List<String> foo() throws Exception{// 顯示丟擲異常
System.out.println("呼叫方法");
// 模擬丟擲異常
System.out.println(1/0);
List<String> list = new ArrayList<>();
list.add("1");
return list;
}
public class RetryUtil {
public static <T> T retry(int maxRetryCount, Supplier<T> supplier, BiFunction<T, Exception, Boolean> consumer) throws Exception{
// 省略...
}
出現這種情況是因為 Supplier 的 get 方法沒有丟擲異常
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
既然你不支援,那就自己寫個唄,於是就有了下面的 DspSupplier,它和 Supplier 的主要區別就是在 get 方法中顯示丟擲了異常
@FunctionalInterface
interface DspSupplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get() throws Exception;
}
於是 retry 方法就變成了下面這樣子
public class RetryUtil {
public static <T> T retry(int maxRetryCount, DspSupplier<T> supplier, BiFunction<T, Exception, Boolean> consumer) throws Exception{
// 省略...
}
使用了自定義的 Supplier 後,呼叫方就沒有 “Unhandled exception” 了
總結
我們平時再開發的過程中,可以嘗試去利用函式式介面去實現一些邏輯的抽取,做成一個工具類,供大家使用,簡化人力,也是對自己編碼能力的一個提升。
上面的案例比較簡單,但麻雀雖小,五臟俱全,也是一個不錯的體驗
歡迎關注公眾號 【每天晒白牙】,獲取最新文章,我們一起交流,共同進步!