0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

責(zé)任鏈設(shè)計(jì)模式詳解

jf_ro2CN3Fa ? 來源:芋道源碼 ? 2023-05-22 15:12 ? 次閱讀

什么是責(zé)任鏈

使用場(chǎng)景

反例

初步改造

缺點(diǎn)

責(zé)任鏈改造

責(zé)任鏈工廠改造

結(jié)語

最近,我讓團(tuán)隊(duì)內(nèi)一位成員寫了一個(gè)導(dǎo)入功能。他使用了責(zé)任鏈模式,代碼堆的非常多,bug 也多,沒有達(dá)到我預(yù)期的效果。

實(shí)際上,針對(duì)導(dǎo)入功能,我認(rèn)為模版方法更合適!為此,隔壁團(tuán)隊(duì)也拿出我們的案例,進(jìn)行了集體 code review。

學(xué)好設(shè)計(jì)模式,且不要為了練習(xí),強(qiáng)行使用!讓原本 100 行就能實(shí)現(xiàn)的功能,寫了 3000 行!對(duì)錯(cuò)暫且不論,我們先一起看看責(zé)任鏈設(shè)計(jì)模式吧!

什么是責(zé)任鏈

責(zé)任鏈模式是一種行為設(shè)計(jì)模式, 允許你將請(qǐng)求沿著處理者鏈進(jìn)行發(fā)送。收到請(qǐng)求后, 每個(gè)處理者均可對(duì)請(qǐng)求進(jìn)行處理, 或?qū)⑵鋫鬟f給鏈上的下個(gè)處理者。

48129cfe-f723-11ed-90ce-dac502259ad0.png

基于 Spring Boot + MyBatis Plus + Vue & Element 實(shí)現(xiàn)的后臺(tái)管理系統(tǒng) + 用戶小程序,支持 RBAC 動(dòng)態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能

項(xiàng)目地址:https://github.com/YunaiV/ruoyi-vue-pro

視頻教程:https://doc.iocoder.cn/video/

使用場(chǎng)景

責(zé)任鏈的使用場(chǎng)景還是比較多的:

多條件流程判斷:權(quán)限控制

ERP 系統(tǒng)流程審批:總經(jīng)理、人事經(jīng)理、項(xiàng)目經(jīng)理

Java 過濾器的底層實(shí)現(xiàn) Filter

如果不使用該設(shè)計(jì)模式,那么當(dāng)需求有所改變時(shí),就會(huì)使得代碼臃腫或者難以維護(hù),例如下面的例子。

反例

假設(shè)現(xiàn)在有一個(gè)闖關(guān)游戲,進(jìn)入下一關(guān)的條件是上一關(guān)的分?jǐn)?shù)要高于 xx:

游戲一共 3 個(gè)關(guān)卡

進(jìn)入第二關(guān)需要第一關(guān)的游戲得分大于等于 80

進(jìn)入第三關(guān)需要第二關(guān)的游戲得分大于等于 90

那么代碼可以這樣寫:

//第一關(guān)
publicclassFirstPassHandler{
publicinthandler(){
System.out.println("第一關(guān)-->FirstPassHandler");
return80;
}
}

//第二關(guān)
publicclassSecondPassHandler{
publicinthandler(){
System.out.println("第二關(guān)-->SecondPassHandler");
return90;
}
}


//第三關(guān)
publicclassThirdPassHandler{
publicinthandler(){
System.out.println("第三關(guān)-->ThirdPassHandler,這是最后一關(guān)啦");
return95;
}
}


//客戶端
publicclassHandlerClient{
publicstaticvoidmain(String[]args){

FirstPassHandlerfirstPassHandler=newFirstPassHandler();//第一關(guān)
SecondPassHandlersecondPassHandler=newSecondPassHandler();//第二關(guān)
ThirdPassHandlerthirdPassHandler=newThirdPassHandler();//第三關(guān)

intfirstScore=firstPassHandler.handler();
//第一關(guān)的分?jǐn)?shù)大于等于80則進(jìn)入第二關(guān)
if(firstScore>=80){
intsecondScore=secondPassHandler.handler();
//第二關(guān)的分?jǐn)?shù)大于等于90則進(jìn)入第二關(guān)
if(secondScore>=90){
thirdPassHandler.handler();
}
}
}
}

那么如果這個(gè)游戲有 100 關(guān),我們的代碼很可能就會(huì)寫成這個(gè)樣子:

if(第1關(guān)通過){
//第2關(guān)游戲
if(第2關(guān)通過){
//第3關(guān)游戲
if(第3關(guān)通過){
//第4關(guān)游戲
if(第4關(guān)通過){
//第5關(guān)游戲
if(第5關(guān)通過){
//第6關(guān)游戲
if(第6關(guān)通過){
//...
}
}
}
}
}
}

這種代碼不僅冗余,并且當(dāng)我們要將某兩關(guān)進(jìn)行調(diào)整時(shí)會(huì)對(duì)代碼非常大的改動(dòng),這種操作的風(fēng)險(xiǎn)是很高的,因此,該寫法非常糟糕。

初步改造

如何解決這個(gè)問題,我們可以通過鏈表將每一關(guān)連接起來,形成責(zé)任鏈的方式,第一關(guān)通過后是第二關(guān),第二關(guān)通過后是第三關(guān)....

這樣客戶端就不需要進(jìn)行多重 if 的判斷了:

publicclassFirstPassHandler{
/**
*第一關(guān)的下一關(guān)是第二關(guān)
*/
privateSecondPassHandlersecondPassHandler;

publicvoidsetSecondPassHandler(SecondPassHandlersecondPassHandler){
this.secondPassHandler=secondPassHandler;
}

//本關(guān)卡游戲得分
privateintplay(){
return80;
}

publicinthandler(){
System.out.println("第一關(guān)-->FirstPassHandler");
if(play()>=80){
//分?jǐn)?shù)>=80并且存在下一關(guān)才進(jìn)入下一關(guān)
if(this.secondPassHandler!=null){
returnthis.secondPassHandler.handler();
}
}

return80;
}
}

publicclassSecondPassHandler{

/**
*第二關(guān)的下一關(guān)是第三關(guān)
*/
privateThirdPassHandlerthirdPassHandler;

publicvoidsetThirdPassHandler(ThirdPassHandlerthirdPassHandler){
this.thirdPassHandler=thirdPassHandler;
}

//本關(guān)卡游戲得分
privateintplay(){
return90;
}

publicinthandler(){
System.out.println("第二關(guān)-->SecondPassHandler");

if(play()>=90){
//分?jǐn)?shù)>=90并且存在下一關(guān)才進(jìn)入下一關(guān)
if(this.thirdPassHandler!=null){
returnthis.thirdPassHandler.handler();
}
}

return90;
}
}

publicclassThirdPassHandler{

//本關(guān)卡游戲得分
privateintplay(){
return95;
}

/**
*這是最后一關(guān),因此沒有下一關(guān)
*/
publicinthandler(){
System.out.println("第三關(guān)-->ThirdPassHandler,這是最后一關(guān)啦");
returnplay();
}
}

publicclassHandlerClient{
publicstaticvoidmain(String[]args){

FirstPassHandlerfirstPassHandler=newFirstPassHandler();//第一關(guān)
SecondPassHandlersecondPassHandler=newSecondPassHandler();//第二關(guān)
ThirdPassHandlerthirdPassHandler=newThirdPassHandler();//第三關(guān)

firstPassHandler.setSecondPassHandler(secondPassHandler);//第一關(guān)的下一關(guān)是第二關(guān)
secondPassHandler.setThirdPassHandler(thirdPassHandler);//第二關(guān)的下一關(guān)是第三關(guān)

//說明:因?yàn)榈谌P(guān)是最后一關(guān),因此沒有下一關(guān)
//開始調(diào)用第一關(guān)每一個(gè)關(guān)卡是否進(jìn)入下一關(guān)卡在每個(gè)關(guān)卡中判斷
firstPassHandler.handler();

}
}

缺點(diǎn)

現(xiàn)有模式的缺點(diǎn):

每個(gè)關(guān)卡中都有下一關(guān)的成員變量并且是不一樣的,形成鏈很不方便

代碼的擴(kuò)展性非常不好

責(zé)任鏈改造

既然每個(gè)關(guān)卡中都有下一關(guān)的成員變量并且是不一樣的,那么我們可以在關(guān)卡上抽象出一個(gè)父類或者接口,然后每個(gè)具體的關(guān)卡去繼承或者實(shí)現(xiàn)。

有了思路,我們先來簡(jiǎn)單介紹一下責(zé)任鏈設(shè)計(jì)模式的基本組成:

抽象處理者(Handler)角色: 定義一個(gè)處理請(qǐng)求的接口,包含抽象處理方法和一個(gè)后繼連接。

具體處理者(Concrete Handler)角色: 實(shí)現(xiàn)抽象處理者的處理方法,判斷能否處理本次請(qǐng)求,如果可以處理請(qǐng)求則處理,否則將該請(qǐng)求轉(zhuǎn)給它的后繼者。

客戶類(Client)角色: 創(chuàng)建處理鏈,并向鏈頭的具體處理者對(duì)象提交請(qǐng)求,它不關(guān)心處理細(xì)節(jié)和請(qǐng)求的傳遞過程。

481c50d2-f723-11ed-90ce-dac502259ad0.png

publicabstractclassAbstractHandler{

/**
*下一關(guān)用當(dāng)前抽象類來接收
*/
protectedAbstractHandlernext;

publicvoidsetNext(AbstractHandlernext){
this.next=next;
}

publicabstractinthandler();
}

publicclassFirstPassHandlerextendsAbstractHandler{

privateintplay(){
return80;
}

@Override
publicinthandler(){
System.out.println("第一關(guān)-->FirstPassHandler");
intscore=play();
if(score>=80){
//分?jǐn)?shù)>=80并且存在下一關(guān)才進(jìn)入下一關(guān)
if(this.next!=null){
returnthis.next.handler();
}
}
returnscore;
}
}

publicclassSecondPassHandlerextendsAbstractHandler{

privateintplay(){
return90;
}

publicinthandler(){
System.out.println("第二關(guān)-->SecondPassHandler");

intscore=play();
if(score>=90){
//分?jǐn)?shù)>=90并且存在下一關(guān)才進(jìn)入下一關(guān)
if(this.next!=null){
returnthis.next.handler();
}
}

returnscore;
}
}

publicclassThirdPassHandlerextendsAbstractHandler{

privateintplay(){
return95;
}

publicinthandler(){
System.out.println("第三關(guān)-->ThirdPassHandler");
intscore=play();
if(score>=95){
//分?jǐn)?shù)>=95并且存在下一關(guān)才進(jìn)入下一關(guān)
if(this.next!=null){
returnthis.next.handler();
}
}
returnscore;
}
}

publicclassHandlerClient{
publicstaticvoidmain(String[]args){

FirstPassHandlerfirstPassHandler=newFirstPassHandler();//第一關(guān)
SecondPassHandlersecondPassHandler=newSecondPassHandler();//第二關(guān)
ThirdPassHandlerthirdPassHandler=newThirdPassHandler();//第三關(guān)

//和上面沒有更改的客戶端代碼相比,只有這里的set方法發(fā)生變化,其他都是一樣的
firstPassHandler.setNext(secondPassHandler);//第一關(guān)的下一關(guān)是第二關(guān)
secondPassHandler.setNext(thirdPassHandler);//第二關(guān)的下一關(guān)是第三關(guān)

//說明:因?yàn)榈谌P(guān)是最后一關(guān),因此沒有下一關(guān)

//從第一個(gè)關(guān)卡開始
firstPassHandler.handler();

}
}

責(zé)任鏈工廠改造

對(duì)于上面的請(qǐng)求鏈,我們也可以把這個(gè)關(guān)系維護(hù)到配置文件中或者一個(gè)枚舉中。我將使用枚舉來教會(huì)大家怎么動(dòng)態(tài)的配置請(qǐng)求鏈并且將每個(gè)請(qǐng)求者形成一條調(diào)用鏈。

4825da08-f723-11ed-90ce-dac502259ad0.png

publicenumGatewayEnum{
//handlerId,攔截者名稱,全限定類名,preHandlerId,nextHandlerId
API_HANDLER(newGatewayEntity(1,"api接口限流","cn.dgut.design.chain_of_responsibility.GateWay.impl.ApiLimitGatewayHandler",null,2)),
BLACKLIST_HANDLER(newGatewayEntity(2,"黑名單攔截","cn.dgut.design.chain_of_responsibility.GateWay.impl.BlacklistGatewayHandler",1,3)),
SESSION_HANDLER(newGatewayEntity(3,"用戶會(huì)話攔截","cn.dgut.design.chain_of_responsibility.GateWay.impl.SessionGatewayHandler",2,null)),
;

GatewayEntitygatewayEntity;

publicGatewayEntitygetGatewayEntity(){
returngatewayEntity;
}

GatewayEnum(GatewayEntitygatewayEntity){
this.gatewayEntity=gatewayEntity;
}
}

publicclassGatewayEntity{

privateStringname;

privateStringconference;

privateIntegerhandlerId;

privateIntegerpreHandlerId;

privateIntegernextHandlerId;
}


publicinterfaceGatewayDao{

/**
*根據(jù)handlerId獲取配置項(xiàng)
*@paramhandlerId
*@return
*/
GatewayEntitygetGatewayEntity(IntegerhandlerId);

/**
*獲取第一個(gè)處理者
*@return
*/
GatewayEntitygetFirstGatewayEntity();
}

publicclassGatewayImplimplementsGatewayDao{

/**
*初始化,將枚舉中配置的handler初始化到map中,方便獲取
*/
privatestaticMapgatewayEntityMap=newHashMap<>();

static{
GatewayEnum[]values=GatewayEnum.values();
for(GatewayEnumvalue:values){
GatewayEntitygatewayEntity=value.getGatewayEntity();
gatewayEntityMap.put(gatewayEntity.getHandlerId(),gatewayEntity);
}
}

@Override
publicGatewayEntitygetGatewayEntity(IntegerhandlerId){
returngatewayEntityMap.get(handlerId);
}

@Override
publicGatewayEntitygetFirstGatewayEntity(){
for(Map.Entryentry:gatewayEntityMap.entrySet()){
GatewayEntityvalue=entry.getValue();
//沒有上一個(gè)handler的就是第一個(gè)
if(value.getPreHandlerId()==null){
returnvalue;
}
}
returnnull;
}
}

publicclassGatewayHandlerEnumFactory{

privatestaticGatewayDaogatewayDao=newGatewayImpl();

//提供靜態(tài)方法,獲取第一個(gè)handler
publicstaticGatewayHandlergetFirstGatewayHandler(){

GatewayEntityfirstGatewayEntity=gatewayDao.getFirstGatewayEntity();
GatewayHandlerfirstGatewayHandler=newGatewayHandler(firstGatewayEntity);
if(firstGatewayHandler==null){
returnnull;
}

GatewayEntitytempGatewayEntity=firstGatewayEntity;
IntegernextHandlerId=null;
GatewayHandlertempGatewayHandler=firstGatewayHandler;
//迭代遍歷所有handler,以及將它們鏈接起來
while((nextHandlerId=tempGatewayEntity.getNextHandlerId())!=null){
GatewayEntitygatewayEntity=gatewayDao.getGatewayEntity(nextHandlerId);
GatewayHandlergatewayHandler=newGatewayHandler(gatewayEntity);
tempGatewayHandler.setNext(gatewayHandler);
tempGatewayHandler=gatewayHandler;
tempGatewayEntity=gatewayEntity;
}
//返回第一個(gè)handler
returnfirstGatewayHandler;
}

/**
*反射實(shí)體化具體的處理者
*@paramfirstGatewayEntity
*@return
*/
privatestaticGatewayHandlernewGatewayHandler(GatewayEntityfirstGatewayEntity){
//獲取全限定類名
StringclassName=firstGatewayEntity.getConference();
try{
//根據(jù)全限定類名,加載并初始化該類,即會(huì)初始化該類的靜態(tài)段
Classclazz=Class.forName(className);
return(GatewayHandler)clazz.newInstance();
}catch(ClassNotFoundException|IllegalAccessException|InstantiationExceptione){
e.printStackTrace();
}
returnnull;
}


}

publicclassGetewayClient{
publicstaticvoidmain(String[]args){
GetewayHandlerfirstGetewayHandler=GetewayHandlerEnumFactory.getFirstGetewayHandler();
firstGetewayHandler.service();
}
}

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實(shí)現(xiàn)的后臺(tái)管理系統(tǒng) + 用戶小程序,支持 RBAC 動(dòng)態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能

項(xiàng)目地址:https://github.com/YunaiV/yudao-cloud

視頻教程:https://doc.iocoder.cn/video/

結(jié)語

設(shè)計(jì)模式有很多,責(zé)任鏈只是其中的一種,我覺得很有意思,非常值得一學(xué)。設(shè)計(jì)模式確實(shí)是一門藝術(shù),仍需努力呀!

審核編輯:彭靜
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 程序
    +關(guān)注

    關(guān)注

    116

    文章

    3761

    瀏覽量

    80754
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4722

    瀏覽量

    68236
  • RBAC
    +關(guān)注

    關(guān)注

    0

    文章

    43

    瀏覽量

    9933

原文標(biāo)題:代碼精簡(jiǎn)10倍,責(zé)任鏈模式y(tǒng)yds

文章出處:【微信號(hào):芋道源碼,微信公眾號(hào):芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    為什么使用菊花配置模式對(duì)FPGA編程會(huì)失敗?

    親愛的先生,我們使用了2個(gè)Vertex 5&amp; spartan 6 FPGA,用于使用菊花配置模式對(duì)這些FPGA進(jìn)行編程。1.我們正在使用xilinx Blaster“平臺(tái)電纜USB
    發(fā)表于 11-07 08:25

    什么是菊花模式 星型模式

    什么是菊花模式 星型模式 菊花模式   菊花
    發(fā)表于 12-05 09:00 ?8491次閱讀

    嵌入式系統(tǒng)的知識(shí)平臺(tái)與平臺(tái)模式詳解

    嵌入式系統(tǒng)的知識(shí)平臺(tái)與平臺(tái)模式詳解 知識(shí)經(jīng)濟(jì)的時(shí)代是一個(gè)以知識(shí)平臺(tái)為中心的市場(chǎng)經(jīng)濟(jì)時(shí)代。嵌入式系統(tǒng)領(lǐng)域的產(chǎn)業(yè)、科技,已從資本經(jīng)濟(jì)時(shí)代封閉
    發(fā)表于 03-29 15:09 ?914次閱讀

    電子行業(yè)供應(yīng)責(zé)任向前邁出一步

    電子行業(yè)供應(yīng)責(zé)任向前邁出一步     瑞士蒙特勒2010年3月11日電 /美通社亞洲/ -- Achilles Information Ltd. 與 Global e-Sustainability Initiati
    發(fā)表于 03-11 18:19 ?456次閱讀

    基于MSP430單片機(jī)低功耗控制與系統(tǒng)工作模式詳解

    基于MSP430單片機(jī)低功耗控制與系統(tǒng)工作模式詳解
    發(fā)表于 10-12 15:29 ?11次下載
    基于MSP430單片機(jī)低功耗控制與系統(tǒng)工作<b class='flag-5'>模式</b><b class='flag-5'>詳解</b>

    區(qū)塊技術(shù)有哪些特點(diǎn)_區(qū)塊技術(shù)應(yīng)用_區(qū)塊技術(shù)的工作原理

    本文以區(qū)塊為中心,主要介紹了區(qū)塊技術(shù)的特點(diǎn)、區(qū)塊的分類、區(qū)塊技術(shù)應(yīng)用以及區(qū)塊技術(shù)的工作原理進(jìn)行
    發(fā)表于 12-18 09:10 ?2w次閱讀

    半導(dǎo)體芯片行業(yè)的運(yùn)作模式是什么(IDM/Fabless/Foundry模式

    本文首先詳解半導(dǎo)體芯片行業(yè)的三種運(yùn)作模式,分別有IDM、Fabless和Foundry模式。其次介紹了半導(dǎo)體芯片及半導(dǎo)體芯片產(chǎn)業(yè)重要環(huán)節(jié),具體的跟隨小編一起來了解一下。
    的頭像 發(fā)表于 05-31 11:25 ?32.6w次閱讀

    C語言設(shè)計(jì)模式的程序資料合集

    之模板模式,C語言設(shè)計(jì)模式之工廠模式,C語言設(shè)計(jì)模式責(zé)任
    發(fā)表于 11-16 08:00 ?4次下載

    HS6621 串口透?jìng)?模式 - [詳解]

    HS6621串口透?jìng)?b class='flag-5'>模式詳解
    發(fā)表于 12-08 18:36 ?32次下載
    HS6621 串口透?jìng)?<b class='flag-5'>模式</b> - [<b class='flag-5'>詳解</b>]

    一起看看責(zé)任設(shè)計(jì)模式吧!

    如何解決這個(gè)問題,我們可以通過鏈表將每一關(guān)連接起來,形成責(zé)任的方式,第一關(guān)通過后是第二關(guān),第二關(guān)通過后是第三關(guān) ....,這樣客戶端就不需要進(jìn)行多重 if 的判斷了
    的頭像 發(fā)表于 07-08 16:25 ?827次閱讀

    什么是責(zé)任?

    責(zé)任模式是行為模式的一種,它將需要觸發(fā)的Handler組成一條,發(fā)送者將請(qǐng)求發(fā)給的第一個(gè)接
    的頭像 發(fā)表于 02-16 14:41 ?884次閱讀

    如何用責(zé)任默認(rèn)優(yōu)雅地進(jìn)行參數(shù)校驗(yàn)

    那么有什么更好的參數(shù)校驗(yàn)的方式呢?本文就推薦一種通過責(zé)任設(shè)計(jì)模式來優(yōu)雅地實(shí)現(xiàn)參數(shù)的校驗(yàn)功能,我們通過一個(gè)用戶注冊(cè)的例子來講明白如何實(shí)現(xiàn)。
    的頭像 發(fā)表于 04-06 15:00 ?435次閱讀

    設(shè)計(jì)模式行為型:責(zé)任模式

    將請(qǐng)求發(fā)送者和請(qǐng)求接受者解耦,讓請(qǐng)求的接受者形成鏈?zhǔn)讲僮?,所有人都能夠接受接受到?qǐng)求,直到有人處理請(qǐng)求。
    的頭像 發(fā)表于 06-06 17:33 ?749次閱讀
    設(shè)計(jì)<b class='flag-5'>模式</b>行為型:<b class='flag-5'>責(zé)任</b><b class='flag-5'>鏈</b><b class='flag-5'>模式</b>

    設(shè)計(jì)模式責(zé)任模式概述

    設(shè)計(jì)模式是一些被反復(fù)使用的、具有普遍性的設(shè)計(jì)解決方案,它們是在特定情境下對(duì)軟件設(shè)計(jì)問題的成功解決方式的總結(jié)和歸納。
    的頭像 發(fā)表于 09-27 09:54 ?630次閱讀
    設(shè)計(jì)<b class='flag-5'>模式</b>之<b class='flag-5'>責(zé)任</b><b class='flag-5'>鏈</b><b class='flag-5'>模式</b>概述

    還在自己實(shí)現(xiàn)責(zé)任?我建議你造輪子之前先看看這個(gè)開源項(xiàng)目

    1. 前言 設(shè)計(jì)模式在軟件開發(fā)中被廣泛使用。通過使用設(shè)計(jì)模式,開發(fā)人員可以更加高效地開發(fā)出高質(zhì)量的軟件系統(tǒng),提高代碼的可讀性、可維護(hù)性和可擴(kuò)展性。 責(zé)任
    的頭像 發(fā)表于 09-20 14:38 ?281次閱讀
    還在自己實(shí)現(xiàn)<b class='flag-5'>責(zé)任</b><b class='flag-5'>鏈</b>?我建議你造輪子之前先看看這個(gè)開源項(xiàng)目