前言
有段時間沒寫文章了,最近沉迷Rust,無法自拔,銹兒有毒;這真是門非常有趣的語言,很多地方的設計,真的是滿足了我所有的向往。
當然,這也不是一門簡單的語言,提出所有權的概念,引入了極多符號:mut、&mut、ref mut、&、*、as_mut、as_ref。。。讓人頭禿。。。
之前看到過一句話,覺得很不錯:學習Rust並不會給你帶來智商上的優越感,但或許會讓你重新愛上編程。
大家如果閱讀過一些開源框架的源碼,可能會發現其中數不盡的抽象類,設計模式拈手而來,在功能框架中,可以使用設計模式隨心所欲的解耦;在實際的復雜業務中,當然也可以應用合適的設計模式。
這篇文章,我會結合較為常見的實際業務場景,探討如何使用合適的設計模式將業務解耦
- 此處的應用絕不是生搬硬套,是我經過深思熟慮,並將較為復雜的業務進行全面重構后,得出的一套行之有效的思路歷程
- 任何一個設計模式都是一個偉大的經驗及其思想總結,千人千面,如果對文章中內容,有不同的意見,希望你能在評論中提出,我們共同探討,共同進步
本文章是一篇弱代碼類型文章,我會畫大量的圖片向大家展示,引用設計模式后,會對原有的業務流程,產生什么樣的影響。
前置知識
這里,需要了解下基礎知識,什么是責任鏈模式和策略模式
責任鏈模式,在很多開源框架中都是有所應用,你如果聽到啥啥攔截器,基本就是責任鏈模式,責任鏈模式的思想很簡單,但是有很多種實現方式
- 最簡單的鏈表實現就和OkHttp的攔截器實現大相徑庭
- OkHttp的攔截器實現和Dio攔截器實現結構相同,但遍歷方式不一樣
- 很多騷操作:我喜歡OkHttp的實現方式,喜歡dio的Api設計,結尾會給出一個結合這倆者思想的通用攔截器
策略模式,或是天生適合業務,同一模塊不同類型業務,如果行為相同,或許就可以考慮使用策略模式去解耦了
責任鏈模式
這邊用Dart寫一個簡單的攔截器,dart和java非常像
- 為了減少語言差異,我就不使用箭頭語法了
- 下划線表示私有
用啥語言不重要,這邊只是用代碼簡單演示下思想
此處實現就用鏈表了;如果,使用數組的形式,需要多寫很多邏輯,數組的優化寫法在結尾給出,此處暫且不表
結構
- 責任鏈的結構,通常有倆種結構
- 鏈表結構:鏈表構建責任鏈,十分便捷的就能和下一節點建立聯系
- 數組結構:數組,用通用的List即可,方便增刪,不固定長度(別費勁的用固定長度Array了,例如:int[]、String[])
- 實現一個鏈表實體很簡單
abstract class InterceptChain<T> {
InterceptChain? next;
void intercept(T data) {
next?.intercept(data);
}
}
實現
- 攔截器實現
/// 該攔截器以最簡單的鏈表實現
abstract class InterceptChain<T> {
InterceptChain? next;
void intercept(T data) {
next?.intercept(data);
}
}
class InterceptChainHandler<T> {
InterceptChain? _interceptFirst;
void add(InterceptChain interceptChain) {
if (_interceptFirst == null) {
_interceptFirst = interceptChain;
return;
}
var node = _interceptFirst!;
while (true) {
if (node.next == null) {
node.next = interceptChain;
break;
}
node = node.next!;
}
}
void intercept(T data) {
_interceptFirst?.intercept(data);
}
}
- 使用
- 調整add順序,就調整了對應邏輯的節點,在整個責任鏈中的順序
- 去掉intercept重寫方法中的super.intercept(data),就能實現攔截后續節點邏輯
void main() {
var intercepts = InterceptChainHandler<String>();
intercepts.add(OneIntercept());
intercepts.add(TwoIntercept());
intercepts.intercept("測試攔截器");
}
class OneIntercept extends InterceptChain<String> {
@override
void intercept(String data) {
data = "$data:OneIntercept";
print(data);
super.intercept(data);
}
}
class TwoIntercept extends InterceptChain<String> {
@override
void intercept(String data) {
data = "$data:TwoIntercept";
print(data);
super.intercept(data);
}
}
- 打印結果
測試攔截器:OneIntercept
測試攔截器:OneIntercept:TwoIntercept
策略模式
結構
- 策略模式最重要的:應該就是對抽象類的設計,對行為的抽象
實現
- 定義抽象類,抽象行為
/// 結合適配器模式的接口適配:抽象必須實現行為,和可選實現行為
abstract class BusinessAction {
///創建相應資源:該行為必須實現
void create();
///可選實現
void dealIO() {}
///可選實現
void dealNet() {}
///可選實現
void dealSystem() {}
///釋放資源:該行為必須實現
void dispose();
}
- 實現策略類
//Net策略
class NetStrategy extends BusinessAction {
@override
void create() {
print("創建Net資源");
}
@override
void dealNet() {
print("處理Net邏輯");
}
@override
void dispose() {
print("釋放Net資源");
}
}
///IO策略
class IOStrategy extends BusinessAction {
@override
void create() {
print("創建IO資源");
}
@override
void dealIO() {
print("處理IO邏輯");
}
@override
void dispose() {
print("釋放IO資源");
}
}
- 使用
void main() {
var type = 1;
BusinessAction strategy;
//不同業務使用不同策略
if (type == 0) {
strategy = NetStrategy();
} else {
strategy = IOStrategy();
}
//開始創建資源
strategy.create();
//......... 省略N多邏輯(其中某些場景,會有用到Net業務,和上面type是關聯的)
//IO業務:開始處理業務
strategy.dealIO();
//......... 省略N多邏輯
//釋放資源
strategy.dispose();
}
- 結果
創建IO資源
處理IO邏輯
釋放IO資源
適合的業務場景
這邊舉一些適合上述設計模式的業務場景,這些場景是真實存在的!
這些真實的業務,使用設計模式解耦和純靠if else懟,完全是倆種體驗!
代碼如詩,這並不是一句玩笑話。
連環彈窗業務
業務描述
連環彈窗奪命call來襲。。。
- A彈窗彈出:有確定和取消按鈕
- 確定按鈕:B彈窗彈出(有查看詳情和取消按鈕)
- 查看詳情按鈕:C彈窗彈出(有同意和拒絕按鈕)
- 同意按鈕:D彈窗彈出(有查看和下一步按鈕)
- 查看按鈕:E彈窗彈出(只有下一步按鈕)
- 下一步按鈕:F彈窗彈出(結束)
- 下一步按鈕:F彈窗彈出(結束)
- 查看按鈕:E彈窗彈出(只有下一步按鈕)
- 拒絕按鈕:流程結束
- 同意按鈕:D彈窗彈出(有查看和下一步按鈕)
- 取消按鈕:流程結束
- 查看詳情按鈕:C彈窗彈出(有同意和拒絕按鈕)
- 取消按鈕:流程結束
- 確定按鈕:B彈窗彈出(有查看詳情和取消按鈕)
好家伙,套娃真是無所不在,真不是我們代碼套娃,實在是業務套娃,手動滑稽.png
- 圖示彈窗業務
直接開搞
看到這個業務,大家會去怎么做呢?
- 有人可能會想,這么簡單的業務還需要想嗎?直接寫啊!
- A:在確定回調里面,跳轉B彈窗
- B:查看詳情按鈕跳轉C彈窗
- 。。。
- 好一通套后,終於寫完了
產品來了,加需求
B和C彈窗之間要加個預覽G彈窗,點擊B的查看詳情按鈕,跳轉預覽G彈窗;預覽G彈窗只有一個確定按鈕,點擊后跳轉C彈窗
- 你心里可能要想了,這特么不是坑爹?
- 業務本來就超吉爾套,我B彈窗里面寫的跳轉代碼要改,傳參要改,而且還要加彈窗!
- 先要去找產品撕比,撕完后
- 然后繼續在屎山上,小心翼翼的再拉了坨shit
- 這座克蘇魯山初成規模
產品又來了,第一稿需求不合理,需要調整需求
交換C和D彈窗位置,邏輯調整:D彈窗點擊下一步的時候,需要加一個校驗請求,通過后跳轉到C彈窗,點擊查看按鈕跳轉彈窗F
- 你眉頭一皺,發現事情沒有表面這么簡單
- 由於初期圖簡單,幾乎都寫在一個文件里,眼花繚亂彈窗回調太多,而且彈窗樣式也不一樣
- 現在改整個流程,導致你整個人腦子嗡嗡響
- 心中怒氣翻涌,找到產品說
- 回來,坐在椅子上,心里想:
- 老夫寫的代碼天衣無縫,這什么幾把需求
- 可惡,這次測試,起碼要給我多提十幾個BUG
- 克蘇魯山開始猙獰
產品飄來,加改需求:如此,如此,,,這般,這般,,,
- 你....
產品:改下,,,然后,扔給你幾十頁的PRD
你看了看這改了幾十版的克蘇魯山,這幾十個彈窗邏輯居然都寫在一個文件里,快一萬行的代碼。。。
- 心里不禁想:
- 本帥比寫的代碼果然牛批,或許這就是藝術!藝術總是曲高和寡,難被人理解!而我的代碼更牛批,連我自己都看不懂了!
- 這代碼行數!這代碼結構!不得拍個照留念下,傳給以后的孩子當傳家寶供着!
- 心里不禁嘚瑟:
- 這塊業務,除了我,還有誰敢動,成為頭兒的心腹,指日可待!
- 但,轉念深思后:事了拂衣去,深藏功與名
重構
隨着業務的逐漸復雜,最初的設計缺點會逐漸暴露;重構有缺陷的代碼流程,變得勢在必行,這會極大的降低維護成本
如果心中對責任鏈模式有一些概念的話,會發現上面的業務,極其適合責任鏈模式!
對上面的業務進行分析,可以明確一些事
- 這個業務是一個鏈式的,有着明確的方向性:單向,從頭到尾指向
- 業務拆分開,可以將一個彈窗作為單顆粒度,一個彈窗作為節點
- 上級的業務節點可以對下級節點攔截(點擊取消,拒絕按鈕,不再進行后續業務)
重構上面的代碼,只要明確思想和流程就行了
第一稿業務
- 業務流程
- 責任鏈
- 代碼:簡寫
void main() {
var intercepts = InterceptChainHandler<String>();
intercepts.add(AIntercept());
intercepts.add(BIntercept());
intercepts.add(CIntercept());
intercepts.add(DIntercept());
intercepts.add(EIntercept());
intercepts.add(FIntercept());
intercepts.intercept("測試攔截器");
}
第二稿業務
- 業務流程
- 責任鏈
- 代碼:簡寫
void main() {
var intercepts = InterceptChainHandler<String>();
intercepts.add(AIntercept());
intercepts.add(BIntercept());
intercepts.add(GIntercept());
intercepts.add(CIntercept());
intercepts.add(DIntercept());
intercepts.add(EIntercept());
intercepts.add(FIntercept());
intercepts.intercept("測試攔截器");
}
第三稿業務
- 業務流程
- 責任鏈
- 代碼:簡寫
void main() {
var intercepts = InterceptChainHandler<String>();
intercepts.add(AIntercept());
intercepts.add(BIntercept());
intercepts.add(GIntercept());
intercepts.add(DIntercept());
intercepts.add(CIntercept());
intercepts.add(EIntercept());
intercepts.add(FIntercept());
intercepts.intercept("測試攔截器");
}
總結
經過責任鏈模式重構后,業務節點被明確的區分開,整個流程從代碼上看,都相當的清楚,維護將變的異常輕松;或許,此時能感受到一些,編程的樂趣了
花樣彈窗業務
業務描述
來描述一個新的業務:這個業務場景真實存在某辦公軟件
- 進入APP首頁后,和后台建立一個長連接
- 后台某些工單處理后,會通知APP處理,此時app會彈出處理工單的彈窗(app頂部)
- 彈窗類型很多:工單處理彈窗,流程審批彈窗,邀請類型彈窗,查看工單詳情彈窗,提交信息彈窗。。。
- 彈窗彈出類型,是根據后台給的Type進行判斷:從而彈出不同類型彈窗、點擊其按鈕,跳轉不同業務,傳遞不同參數。
分析
確定設計
這個業務,是一種漸變性的引導你搭建克蘇魯代碼山
- 在前期開發的時候,一般只有倆三種類型彈窗,前期十分好做;根本不用考慮如何設計,抬手一行代碼,反手一行代碼,就能搞定
- 但是后來整個業務會漸漸的鬼畜,不同類型會慢慢加到幾十種之多!!!
首先這個業務,使用責任鏈模式,肯定是不合適的,因為彈窗之間的耦合性很低,並沒有什么明確的上下游關系
但是,這個業務使用策略模式非常的合適!
- type明確:不同類型彈出不同彈窗,按鈕執行不同邏輯
- 抽象行為明確:一個按鈕就是一種行為,不同行為的實現邏輯大相徑庭
抽象行為
多樣彈窗的行為抽象,對應其按鈕就行了
確定、取消、同意、拒絕、查看詳情、我知道了、提交
直接畫圖來表示吧
實現
來看下簡要的代碼實現,代碼不重要,重要的是思想,這邊簡要的看下代碼實現流程
- 抽象基類
/// 默認實現拋異常,可提醒未實現方法被誤用
abstract class DialogAction {
///確定
void onConfirm() {
throw 'DialogAction:not implement onConfirm()';
}
///取消
void onCancel() {
throw 'DialogAction:not implement onCancel()';
}
///同意
void onAgree() {
throw 'DialogAction:not implement onAgree()';
}
///拒絕
void onRefuse() {
throw 'DialogAction:not implement onRefuse()';
}
///查看詳情
void onDetail() {
throw 'DialogAction:not implement onDetail()';
}
///我知道了
void onKnow() {
throw 'DialogAction:not implement onKnow()';
}
///提交
void onSubmit() {
throw 'DialogAction:not implement onSubmit()';
}
}
- 實現邏輯類
class OneStrategy extends DialogAction {
@override
void onConfirm() {
print("確定");
}
@override
void onCancel() {
print("取消");
}
}
class TwoStrategy extends DialogAction{
@override
void onAgree() {
print("同意");
}
@override
void onRefuse() {
print("拒絕");
}
}
//........省略其他實現
- 使用
void main() {
//根據接口獲取
var type = 1;
DialogAction strategy;
switch (type) {
case 0:
strategy = DefaultStrategy();
break;
case 1:
strategy = OneStrategy();
break;
case 2:
strategy = TwoStrategy();
break;
case 3:
strategy = ThreeStrategy();
break;
case 4:
strategy = FourStrategy();
break;
case 5:
strategy = FiveStrategy();
break;
default:
strategy = DefaultStrategy();
break;
}
//聚合彈窗按鈕觸發事件(不同彈窗的確定按鈕,皆可聚合為一個onConfirm事件,其它同理)
BusinessDialog(
//通過傳入的type,顯示對應類型的彈窗
type: type,
//確定按鈕
onConfirm: () {
strategy.onConfirm();
},
//取消按鈕
onCancel: () {
strategy.onCancel();
},
//同意按鈕
onAgree: () {
strategy.onAgree();
},
//拒絕按鈕
onRefuse: () {
strategy.onRefuse();
},
//查看詳情按鈕
onDetail: () {
strategy.onDetail();
},
//我知道了按鈕
onKnow: () {
strategy.onKnow();
},
//提交按鈕
onSubmit: () {
strategy.onSubmit();
},
);
}
- 圖示
一個復雜業務場景的演變
我們看下,一個簡單的提交業務流,怎么逐漸變的猙獰
我會逐漸給出一個合適的解決方案,如果大家有更好的想法,務必在評論區告訴鄙人
業務描述:我們的車子因不可抗原因壞了,要去維修廠修車,工作人員開始登記這個損壞車輛。。。
業務的演變
第一稿
初始業務
登記一個維修車輛的流程,實際上還是滿麻煩的
- 登記一個新車,需要將車輛詳細信息登記清楚:車牌、車架、車型號、車輛類型、進出場時間、油量、里程。。。
- 還需要登記一下用戶信息:姓名、手機號、是否隸屬公司。。。
- 登記車損程度:車頂、車底、方向盤、玻璃、離合器、剎車。。。
- 車內物品:車座皮套、工具。。。
- 以及其他我沒想到的。。。
- 最后:提交所有登記好的信息
第一稿,業務流程十分清晰,細節復雜,但是做起來不難
第二稿(實際是多稿聚合):增加下述幾個流程
外部登記:外部登記了一個維修車輛部分信息(后台,微信小程序,H5等等),需要在app上完善信息,提交接口不同(必帶車牌號)
快捷洗車:洗車業務極其常見,快捷生成對應信息,提交接口不同
預約訂單登記:預約好了車輛一部分一些信息,可快捷登記,提交接口不同(必帶車牌號)
因為登記維修車輛流程,登記車輛信息流程極其細致繁瑣,我們決定復用登記新車模塊
- 因為此處邏輯大多涉及開頭和結尾,中間登記車輛信息操作幾乎未改動,復用想法是可行的
- 如果增加車輛登記項,新的三個流程也必須提交這些信息;所以,復用勢在必行
因為這一稿需求,業務也變得愈加復雜
第三稿
現在要針對不同的車輛類型,做不同的處理;車類型分:個人車,集團車
不同類型的登記,在提交的時候,需要校驗不同的信息;校驗不通過,需要提示用戶,並且不能進行提交流程
提交后,需要處理下通用業務,然后跳轉到某個頁面
第三稿的描述不多,但是,大大的增加了復雜度
- 尤其是不同類型校驗過程還不同,還能中斷后續提交流程
- 提交流程后,還需要跳轉通用頁面
開發探討
第一稿
- 業務流程
- 開發
正常流程開發、、、
第二稿
- 業務流程
- 思考
對於第二稿業務,可以好好考慮下,怎么去設計?
開頭和結尾需要單獨寫判斷,去處理不同流程的業務,這至少要寫倆個大的判斷模塊,接受數據的入口模塊可能還要寫判斷
這樣就非常適合策略模式去做了
開頭根據執行的流程,選擇相應的策略對象,后續將邏輯塊替換抽象的策略方法就OK了,大致流程如下
第三稿
業務流程
探討
-
第三稿的需求,實際上,已經比較復雜了
- 整個流程中摻雜着不同業務流程處理,不同流程邏輯又擁有阻斷下游機制(綠色模塊)
- 下游邏輯又會合流(結尾)的多種變換
-
在這一稿的需求
- 使用策略模式肯定是可以的
- 阻斷那塊(綠色模塊)需要單獨處理下:
抽象方法應該擁有返回值,外層根據返回值,判斷是否進行后續流程
- 但!這!也太不優雅了!
-
思考上面業務一些特性
- 攔截下游機制
- 上游到下游、方向明確
- 隨時可能插入新的業務流程。。。
可以用責任鏈模式!但,需要做一些小改動!這地方,我們可以將頻繁變動的模塊用責任鏈模式全都隔離出來
- 看下,使用責任鏈模式改造后流程圖
瀏覽上述流程圖可發現,本來是極度雜亂糅合的業務,可以被設計相對更加平行的結構
-
對於上述流程,可以進一步分析,並進一步簡化:對整體業務分析,我們需要去關注其變或不變的部分
- 不變:整體業務變動很小的是,登記信息流程(主體邏輯這塊),此處的相關變動是很小的,對所有流程也是共用的部分
- 變:可以發現,開頭和結尾是變動更加頻繁的部分,我們可以對此處邏輯進行整體的抽象
-
抽象多變的開頭和結尾
- 所以我們抽象攔截類,可以做一些調整
abstract class InterceptChainTwice<T> {
InterceptChainTwice? next;
void onInit(T data) {
next?.onInit(data);
}
void onSubmit(T data) {
next?.onSubmit(data);
}
}
來看下簡要的代碼實現,代碼不重要,主要看看實現流程和思想
- 抽象攔截器
abstract class InterceptChainTwice<T> {
InterceptChainTwice? next;
void onInit(T data) {
next?.onInit(data);
}
void onSubmit(T data) {
next?.onSubmit(data);
}
}
class InterceptChainTwiceHandler<T> {
InterceptChainTwice? _interceptFirst;
void add(InterceptChainTwice interceptChain) {
if (_interceptFirst == null) {
_interceptFirst = interceptChain;
return;
}
var node = _interceptFirst!;
while (true) {
if (node.next == null) {
node.next = interceptChain;
break;
}
node = node.next!;
}
}
void onInit(T data) {
_interceptFirst?.onInit(data);
}
void onSubmit(T data) {
_interceptFirst?.onSubmit(data);
}
}
- 實現攔截器
/// 開頭通用攔截器
class CommonIntercept extends InterceptChainTwice<String> {
@override
void onInit(String data) {
//如果有車牌,請求接口,獲取數據
//.................
//填充頁面
super.onInit(data);
}
}
/// 登記新車攔截器
class RegisterNewIntercept extends InterceptChainTwice<String> {
@override
void onInit(String data) {
//處理開頭針對登記新車的單獨邏輯
super.onInit(data);
}
@override
void onSubmit(String data) {
var isPass = false;
//如果校驗不過,攔截下游邏輯
if (!isPass) {
return;
}
// ......
super.onSubmit(data);
}
}
/// 省略其他實現
- 使用
void main() {
var type = 0;
var intercepts = InterceptChainTwiceHandler();
intercepts.add(CommonIntercept());
intercepts.add(CarTypeDealIntercept());
if (type == 0) {
//登記新車
intercepts.add(RegisterNewCarIntercept());
} else if (type == 1) {
//外部登記
intercepts.add(OutRegisterIntercept());
} else if (type == 2) {
//快捷洗車
intercepts.add(FastWashIntercept());
} else {
//預約訂單登記
intercepts.add(OrderRegisterIntercept());
}
intercepts.add(TailIntercept());
//業務開始
intercepts.onInit("傳入數據源");
//開始處理N多邏輯
//............................................................
//經歷了N多邏輯
//提交按鈕觸發事件
SubmitBtn(
//提交按鈕
onSubmit: () {
intercepts.onSubmit("傳入提交數據");
},
);
}
總結
關於代碼部分,關鍵的代碼,我都寫出來,用心看看,肯定能明白我寫的意思
也不用找我要完整代碼了,這些業務demo代碼寫完后,就刪了
本欄目這個業務,實際上是非常常見的的一個業務,一個提交流程與很多其它的流程耦合,整個業務就會慢慢的變的鬼畜,充滿各種判斷,很容易讓人陷入泥濘,或許,此時可以對已有業務進行思考,如何進行合理的優化
該業務的演變歷程,和開發改造是本人的一次思路歷程,如大家有更好的思路,還請不吝賜教。
通用攔截器
我結合OkHttp的思想和Dio的API,封裝了倆個通用攔截器,這邊貼下代碼,如果哪里有什么不足,請及時告知本人
說明下:這是Dart版本的
抽象單方法
///一層通用攔截器,T的類型必須一致
abstract class InterceptSingle<T> {
void intercept(T data, SingleHandler handler) => handler.next(data);
}
///添加攔截器,觸發攔截器方法入口
class InterceptSingleHandler<T> {
_InterceptSingleHandler _handler = _InterceptSingleHandler(intercepts: []);
void add(InterceptSingle intercept) {
//一種類型的攔截器只能添加一次
for (var item in _handler.intercepts) {
if (item.runtimeType == intercept.runtimeType) {
return;
}
}
_handler.intercepts.add(intercept);
}
void delete(InterceptSingle intercept) {
_handler.intercepts.remove(intercept);
}
void intercept(T data) {
_handler.next(data);
}
}
///------------實現不同處理器 參照 dio api設計 和 OkHttp實現思想---------------
abstract class SingleHandler {
/// span: 設置該參數,可控跨越多級節點
/// 默認0,則不跨越節點(遍歷所有節點)
next(dynamic data, {int span = 0});
}
///實現init處理器
class _InterceptSingleHandler extends SingleHandler {
List<InterceptSingle> intercepts;
int index;
_InterceptSingleHandler({
this.index = 0,
required this.intercepts,
});
@override
next(dynamic data, {int span = 0}) {
if ((index + span) >= intercepts.length) return;
var intercept = intercepts[index + span];
var handler = _InterceptSingleHandler(
index: index + (span + 1),
intercepts: intercepts,
);
intercept.intercept(data, handler);
}
}
抽象雙方法
///倆層通用攔截器,T的類型必須一致
abstract class InterceptTwice<T> {
void onInit(T data, TwiceHandler handler) => handler.next(data);
void onSubmit(T data, TwiceHandler handler) => handler.next(data);
}
///添加攔截器,觸發攔截器方法入口
class InterceptTwiceHandler<T> {
_TwiceInitHandler _init = _TwiceInitHandler(intercepts: []);
_TwiceSubmitHandler _submit = _TwiceSubmitHandler(intercepts: []);
void add(InterceptTwice intercept) {
//一種類型的攔截器只能添加一次
for (var item in _init.intercepts) {
if (item.runtimeType == intercept.runtimeType) {
return;
}
}
_init.intercepts.add(intercept);
_submit.intercepts.add(intercept);
}
void delete(InterceptTwice intercept) {
_init.intercepts.remove(intercept);
_submit.intercepts.remove(intercept);
}
void onInit(T data) {
_init.next(data);
}
void onSubmit(T data) {
_submit.next(data);
}
}
///------------實現不同處理器 參照 dio api設計 和 OkHttp實現思想---------------
abstract class TwiceHandler {
/// span: 設置該參數,可控跨越多級節點
/// 默認0,則不跨越節點(遍歷所有節點)
next(dynamic data, {int span = 0});
}
///實現init處理器
class _TwiceInitHandler extends TwiceHandler {
List<InterceptTwice> intercepts;
int index;
_TwiceInitHandler({
this.index = 0,
required this.intercepts,
});
@override
next(dynamic data, {int span = 0}) {
if ((index + span) >= intercepts.length) return;
var intercept = intercepts[index + span];
var handler = _TwiceInitHandler(
index: index + (span + 1),
intercepts: intercepts,
);
intercept.onInit(data, handler);
}
}
///實現submit處理器
class _TwiceSubmitHandler extends TwiceHandler {
List<InterceptTwice> intercepts;
int index;
_TwiceSubmitHandler({
this.index = 0,
required this.intercepts,
});
@override
next(dynamic data, {int span = 0}) {
if ((index + span) >= intercepts.length) {
return;
}
var intercept = intercepts[index + span];
var handler = _TwiceSubmitHandler(
index: index + (span + 1),
intercepts: intercepts,
);
intercept.onSubmit(data, handler);
}
}
最后
第一次,寫這種結合業務的文章
如有收獲,還請點個贊,讓我感受一下,各位是否讀有所獲~~
感謝閱讀,下次再會~~