Thisisacommunitythatmaybeusefultoyou
One-to-onecommunication/interviewbrochure/resumeoptimization/jobsearchquestions,welcometojointhe”YudaoRapidDevelopmentPlatform“KnowledgePlanet.ThefollowingissomeinformationprovidedbyPlanet:
“ProjectPractice(Video)”:Learnfrombooks,“practice”frompastevents
“InternetHighFrequencyInterviewQuestions”:Studyingwithyourresume,springblossoms
“ArchitecturexSystemDesign”:Overcomingdifficultiesandmasteringhigh-frequencyinterviewscenarioquestions
“AdvancingJavaLearningGuide”:systematiclearning,themainstreamtechnologystackoftheInternet
“Must-readJavaSourceCodeColumn”:Knowwhatitisandwhyitisso
Thisisanopensourceprojectthatmaybeusefultoyou
DomesticStarisa100,000+opensourceproject.Thefront-endincludesmanagementbackend+WeChatapplet,andtheback-endsupportsmonomerandmicroservicearchitecture.
FunctionscoverRBACpermissions,SaaSmulti-tenancy,datapermissions,mall,payment,workflow,large-screenreports,WeChatpublicaccount,etc.:
Bootaddress:https://gitee.com/zhijiantianya/ruoyi-vue-pro
Cloudaddress:https://gitee.com/zhijiantianya/yudao-cloud
Videotutorial:https://doc.iocoder.cn
Source:Internet
-
Whatischainofresponsibility
-
scenestobeused
-
Counterexample
-
preliminaryrenovation
-
shortcoming
-
Responsibilitychaintransformation
-
Responsibilitychainfactorytransformation
-
-
Conclusion
Recently,Ihadamemberofmyteamwriteanimportfunction.Heusedthechainofresponsibilitymodel,whichresultedinalotofcodeandmanybugs.ItdidnotachievetheresultsIexpected.
Infact,fortheimportfunction,Ithinkthetemplatemethodismoresuitable!Tothisend,theteamnextdooralsotookoutourcaseandconductedacollectivecodereview.
Learndesignpatternswell,anddon’tforcethemtousethemjustforpractice!Afunctionthatcouldhavebeenimplementedin100linesnowtook3,000linestowrite!Regardlessofwhetheritisrightorwrong,let’stakealookatthechainofresponsibilitydesignpatternfirst!
Whatisthechainofresponsibility
TheChainofResponsibilitypatternisabehavioraldesignpatternthatallowsyoutosendrequestsalongachainofhandlers.Afterreceivingarequest,eachhandlercanprocesstherequestorpassitontothenexthandlerinthechain.
Backendmanagementsystem+userappletimplementedbasedonSpringBoot+MyBatisPlus+Vue&Element,supportingRBACdynamicpermissions,multi-tenancy,datapermissions,workflow,three-partylogin,payment,SMS,mallandotherfunctions
Projectaddress:https://github.com/YunaiV/ruoyi-vue-pro
Videotutorial:https://doc.iocoder.cn/video/
Usagescenarios
Therearestillmanyusagescenariosforchainofresponsibility:
-
Multi-conditionprocessjudgment:permissioncontrol
-
ERPsystemprocessapproval:generalmanager,personnelmanager,projectmanager
-
TheunderlyingimplementationofJavafilterFilter
Ifthisdesignpatternisnotused,thecodewillbebloatedordifficulttomaintainwhentherequirementschange,suchasthefollowingexample.
Counterexample
Supposethereisalevel-breakinggame.Theconditionforenteringthenextlevelisthatthescoreofthepreviouslevelishigherthanxx:
-
Thegamehas3levelsintotal
-
Enteringthesecondlevelrequiresagamescoreofgreaterthanorequalto80inthefirstlevel.
-
Enteringthethirdlevelrequiresagamescoreof90ormoreinthesecondlevel.
Thenthecodecanbewrittenlikethis:
//Firstlevel publicclassFirstPassHandler{ publicinthandler(){ System.out.println("FirstPass-->FirstPassHandler"); return80; } } //Secondlevel publicclassSecondPassHandler{ publicinthandler(){ System.out.println("SecondPass-->SecondPassHandler"); return90; } } //Thethirdlevel publicclassThirdPassHandler{ publicinthandler(){ System.out.println("Thethirdlevel-->ThirdPassHandler,thisisthelastlevel"); return95; } } //Client publicclassHandlerClient{ publicstaticvoidmain(String[]args){ FirstPassHandlerfirstPassHandler=newFirstPassHandler();//Firstlevel SecondPassHandlersecondPassHandler=newSecondPassHandler();//Secondlevel ThirdPassHandlerthirdPassHandler=newThirdPassHandler();//Thirdlevel intfirstScore=firstPassHandler.handler(); //Thescoreinthefirstlevelisgreaterthanorequalto80,thenenterthesecondlevel if(firstScore>=80){ intsecondScore=secondPassHandler.handler(); //Ifthescoreinthesecondlevelisgreaterthanorequalto90,enterthesecondlevel. if(secondScore>=90){ thirdPassHandler.handler(); } } } }
Soifthisgamehas100levels,ourcodewillprobablybewrittenlikethis:
if(Level1passed){ //Level2Game if(Level2passed){ //Level3Game if(Level3passed){ //Level4Game if(Level4passed){ //Level5Game if(Level5passed){ //Level6Game if(Level6passed){ //... } } } } } }
Thiskindofcodeisnotonlyredundant,butwhenwewanttoadjustcertainlevels,itwillcauseverylargechangestothecode.Theriskofthisoperationisveryhigh,sothewritingmethodisverybad.
Initialrenovation
Howtosolvethisproblem,wecanconnecteachlevelthroughalinkedlisttoformachainofresponsibility.Afterpassingthefirstlevel,thereisthesecondlevel,andafterpassingthesecondlevel,thereisthethirdlevel….
Inthisway,theclientdoesnotneedtoperformmultipleifjudgments:
publicclassFirstPassHandler{ /** *Thenextlevelafterthefirstlevelisthesecondlevel */ privateSecondPassHandlersecondPassHandler; publicvoidsetSecondPassHandler(SecondPassHandlersecondPassHandler){ this.secondPassHandler=secondPassHandler; } //Thegamescoreforthislevel privateintplay(){ return80; } publicinthandler(){ System.out.println("FirstPass-->FirstPassHandler"); if(play()>=80){ //Score>=80andthenextlevelexistsbeforeenteringthenextlevel if(this.secondPassHandler!=null){ returnthis.secondPassHandler.handler(); } } return80; } } publicclassSecondPassHandler{ /** *Thenextleveloflevel2islevel3 */ privateThirdPassHandlerthirdPassHandler; publicvoidsetThirdPassHandler(ThirdPassHandlerthirdPassHandler){ this.thirdPassHandler=thirdPassHandler; } //Thegamescoreforthislevel privateintplay(){ return90; } publicinthandler(){ System.out.println("SecondPass-->SecondPassHandler"); if(play()>=90){ //Score>=90andthenextlevelexistsbeforeenteringthenextlevel if(this.thirdPassHandler!=null){ returnthis.thirdPassHandler.handler(); } } return90; } } publicclassThirdPassHandler{ //Thegamescoreforthislevel privateintplay(){ return95; } /** *Thisisthelastlevel,sothereisnonextlevel */ publicinthandler(){ System.out.println("Thethirdlevel-->ThirdPassHandler,thisisthelastlevel"); returnplay(); } } publicclassHandlerClient{ publicstaticvoidmain(String[]args){ FirstPassHandlerfirstPassHandler=newFirstPassHandler();//Firstlevel SecondPassHandlersecondPassHandler=newSecondPassHandler();//Secondlevel ThirdPassHandlerthirdPassHandler=newThirdPassHandler();//Thirdlevel firstPassHandler.setSecondPassHandler(secondPassHandler);//Thenextlevelofthefirstlevelisthesecondlevel secondPassHandler.setThirdPassHandler(thirdPassHandler);//Thenextlevelofthesecondlevelisthethirdlevel //Explanation:Becausethethirdlevelisthelastlevel,thereisnonextlevel. //Startcallingthefirstlevel.Whethereachlevelentersthenextlevelisjudgedineachlevel. firstPassHandler.handler(); } }
Disadvantages
Disadvantagesofexistingmodel:
-
Eachlevelhasmembervariablesforthenextlevelandtheyaredifferent.Itisveryinconvenienttoformachain.
-
Thescalabilityofthecodeisverypoor
Reformofresponsibilitychain
Sinceeachlevelhasmembervariablesofthenextlevelandtheyaredifferent,wecanabstractaparentclassorinterfaceonthelevel,andtheneachspecificlevelcaninheritorimplementit.
Withtheideainmind,let’sfirstbrieflyintroducethebasiccomponentsofthechainofresponsibilitydesignpattern:
-
Abstracthandler(Handler)role:Definesaninterfaceforprocessingrequests,includingabstractprocessingmethodsandasubsequentconnection.
-
ConcreteHandlerrole:Implementtheprocessingmethodoftheabstracthandlertodeterminewhethertherequestcanbeprocessed.Iftherequestcanbeprocessed,processit,otherwisetherequestwillbetransferredtoitssuccessor.
-
Clientrole:Createsaprocessingchainandsubmitsarequesttothespecifichandlerobjectofthechainhead.Itdoesnotcareabouttheprocessingdetailsandrequestdeliveryprocess.
publicabstractclassAbstractHandler{ /** *Thenextlevelusesthecurrentabstractclasstoreceive */ protectedAbstractHandlernext; publicvoidsetNext(AbstractHandlernext){ this.next=next; } publicabstractinthandler(); } publicclassFirstPassHandlerextendsAbstractHandler{ privateintplay(){ return80; } @Override publicinthandler(){ System.out.println("FirstPass-->FirstPassHandler"); intscore=play(); if(score>=80){ //Score>=80andthenextlevelexistsbeforeenteringthenextlevel if(this.next!=null){ returnthis.next.handler(); } } returnscore; } } publicclassSecondPassHandlerextendsAbstractHandler{ privateintplay(){ return90; } publicinthandler(){ System.out.println("SecondPass-->SecondPassHandler"); intscore=play(); if(score>=90){ //Score>=90andthenextlevelexistsbeforeenteringthenextlevel if(this.next!=null){ returnthis.next.handler(); } } returnscore; } } publicclassThirdPassHandlerextendsAbstractHandler{ privateintplay(){ return95; } publicinthandler(){ System.out.println("ThirdPass-->ThirdPassHandler"); intscore=play(); if(score>=95){ //Score>=95andthenextlevelexistsbeforeenteringthenextlevel if(this.next!=null){ returnthis.next.handler(); } } returnscore; } } publicclassHandlerClient{ publicstaticvoidmain(String[]args){ FirstPassHandlerfirstPassHandler=newFirstPassHandler();//Firstlevel SecondPassHandlersecondPassHandler=newSecondPassHandler();//Secondlevel ThirdPassHandlerthirdPassHandler=newThirdPassHandler();//Thirdlevel //Comparedwiththeunchangedclientcodeabove,onlythesetmethodherehaschanged,everythingelseisthesame firstPassHandler.setNext(secondPassHandler);//Thenextlevelofthefirstlevelisthesecondlevel secondPassHandler.setNext(thirdPassHandler);//Thenextlevelofthesecondlevelisthethirdlevel //Explanation:Becausethethirdlevelisthelastlevel,thereisnonextlevel. //Startfromthefirstlevel firstPassHandler.handler(); } }
Responsibilitychainfactorytransformation
Fortheaboverequestchain,wecanalsomaintainthisrelationshipinaconfigurationfileoranenumeration.Iwilluseenumerationstoteachyouhowtodynamicallyconfiguretherequestchainandformacallchainforeachrequester.
publicenumGatewayEnum{ //handlerId,interceptorname,fullyqualifiedclassname,preHandlerId,nextHandlerId API_HANDLER(newGatewayEntity(1,"apiinterfacecurrentlimit","cn.dgut.design.chain_of_responsibility.GateWay.impl.ApiLimitGatewayHandler",null,2)), BLACKLIST_HANDLER(newGatewayEntity(2,"BlacklistInterception","cn.dgut.design.chain_of_responsibility.GateWay.impl.BlacklistGatewayHandler",1,3)), SESSION_HANDLER(newGatewayEntity(3,"UserSessionInterception","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{ /** *GetconfigurationitemsbasedonhandlerId *@paramhandlerId *@return */ GatewayEntitygetGatewayEntity(IntegerhandlerId); /** *Getthefirsthandler *@return */ GatewayEntitygetFirstGatewayEntity(); } publicclassGatewayImplimplementsGatewayDao{ /** *Initialization,initializethehandlerconfiguredintheenumerationintothemapforeasyaccess */ privatestaticMap<Integer,GatewayEntity>gatewayEntityMap=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.Entry<Integer,GatewayEntity>entry:gatewayEntityMap.entrySet()){ GatewayEntityvalue=entry.getValue(); //Theonewithouttheprevioushandleristhefirstone if(value.getPreHandlerId()==null){ returnvalue; } } returnnull; } } publicclassGatewayHandlerEnumFactory{ privatestaticGatewayDaogatewayDao=newGatewayImpl(); //Providestaticmethodtogetthefirsthandler publicstaticGatewayHandlergetFirstGatewayHandler(){ GatewayEntityfirstGatewayEntity=gatewayDao.getFirstGatewayEntity(); GatewayHandlerfirstGatewayHandler=newGatewayHandler(firstGatewayEntity); if(firstGatewayHandler==null){ returnnull; } GatewayEntitytempGatewayEntity=firstGatewayEntity; IntegernextHandlerId=null; GatewayHandlertempGatewayHandler=firstGatewayHandler; //Iteratethroughallhandlersandlinkthem while((nextHandlerId=tempGatewayEntity.getNextHandlerId())!=null){ GatewayEntitygatewayEntity=gatewayDao.getGatewayEntity(nextHandlerId); GatewayHandlergatewayHandler=newGatewayHandler(gatewayEntity); tempGatewayHandler.setNext(gatewayHandler); tempGatewayHandler=gatewayHandler; tempGatewayEntity=gatewayEntity; } //Returnthefirsthandler returnfirstGatewayHandler; } /** *Reflectionmaterializesspecificprocessors *@paramfirstGatewayEntity *@return */ privatestaticGatewayHandlernewGatewayHandler(GatewayEntityfirstGatewayEntity){ //Getthefullyqualifiedclassname StringclassName=firstGatewayEntity.getConference(); try{ //Loadandinitializetheclassbasedonthefullyqualifiedclassname,whichwillinitializethestaticsectionoftheclass Class<?>clazz=Class.forName(className); return(GatewayHandler)clazz.newInstance(); }catch(ClassNotFoundException|IllegalAccessException|InstantiationExceptione){ e.printStackTrace(); } returnnull; } } publicclassGetewayClient{ publicstaticvoidmain(String[]args){ GetewayHandlerfirstGetewayHandler=GetewayHandlerEnumFactory.getFirstGetewayHandler(); firstGetewayHandler.service(); } }
Backendmanagementsystem+userappletimplementedbasedonSpringCloudAlibaba+Gateway+Nacos+RocketMQ+Vue&Element,supportingRBACdynamicpermissions,multi-tenancy,datapermissions,workflow,three-partylogin,payment,SMS,mallandotherfunctions
Projectaddress:https://github.com/YunaiV/yudao-cloud
Videotutorial:https://doc.iocoder.cn/video/
Conclusion
Therearemanydesignpatterns,andchainofresponsibilityisjustoneofthem.Ifinditveryinterestingandworthlearning.Designpatternisindeedanart,anditstillrequireshardwork!
Welcometojoinmyknowledgeplanetandcomprehensivelyimproveyourtechnicalcapabilities.
Tojoin,“Longpress”or“Scan”theQRcodebelow:
Planet’scontentincludes:projectpractice,interviewsandrecruitment,sourcecodeanalysis,andlearningroutes.
Ifthearticleishelpful,pleasereaditandforwardit. Thankyouforyoursupport(*^__^*)