Code simplification 10 times, responsibility chain model yyds

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(*^__^*)