In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article shows you why the code in web development becomes more and more messy, concise and easy to understand, which will definitely brighten your eyes. I hope you can get something through the detailed introduction of this article.
Purpose
Before you start learning about the chain of responsibility, take a look at the common problems in development. The following is the code used by the front end to handle the API error code:
Const httpErrorHandler = (error) = > {const errorStatus = error.response.status; if (errorStatus = 400) {console.log ('did you submit something strange?') ;} if (errorStatus = 401) {console.log ('login required!') ;} if (errorStatus = 403) {console.log ('are you trying to steal something bad?') ;} if (errorStatus = 404) {console.log ('there's nothing here');}}
Of course, there can't be only one line of console in a real project, which is a simplified version of the principle.
The httpErrorHandler in the code will receive the API response error and handle the error status code differently, so the code needs a lot of if (or switch) to determine what needs to be executed currently, and when you want to add handling code to a new error, you have to go to httpErrorHandler to modify the code.
Although it is inevitable to modify the code frequently, doing so can lead to several problems, as explained below according to the principles of SOLID's single responsibility (Single responsibility) and open closure (open/close):
Single responsibility (Single responsibility)
To put it simply, a single responsibility is to do only one thing. The previous httpErrorHandler method, from a usage point of view, is to give it the error object and let it handle it according to the error code. It looks as if you are doing the single thing of "error handling", but from an implementation point of view, it writes all the handling logic for different errors in httpErrorHandler, which can lead to having to read a lot of irrelevant code when you only want to change the logic with error code 400.
Open and closed principle (open/close)
The principle of opening and closing means not to change the core logic that has been written, but at the same time to be able to expand the original function due to the increase of demand, that is, to open and expand the function, and to close and modify the original correct logic at the same time. Looking back at httpErrorHandler, if you need to add a processing logic for error code 405 (to expand the new function), you need to modify the code in httpErrorHandler (modify the original correct logic), which can easily lead to errors in the code that was executed correctly.
Since there are so many flaws in httpErrorHandler, what should we do?
Problem-solving separation logic
Let httpErrorHandler conform to the single principle first. First, the processing logic of each error is divided into methods:
Const response400 = () = > {console.log ('did you submit something strange?') ;}; const response401 = () = > {console.log ('login required!') ;}; const response403 = () = > {console.log ('do you want to steal something bad?') ;}; const response404 = () = > {console.log ('there's nothing here.');}; const httpErrorHandler = (error) = > {const errorStatus = error.response.status; if (errorStatus = = 400) {response400 ();} if (errorStatus = 401) {response401 ();} if (errorStatus = 403) {response403 ();} if (errorStatus = = 404) {response404 () }}
Although it's just a method to split the logic of each block, it already allows us to modify the error handling of a status code without having to read a lot of code in httpErrorHandler.
The operation of separating logic alone also makes httpErrorHandler conform to the open and closed principle, because when the error handling logic is divided into methods, it is tantamount to encapsulating the completed code. When it is necessary to add error handling logic to httpErrorHandler, it will not affect other methods of error handling logic (closed modification), but create a new response405 method. And add new condition judgment to httpErrorHandler (open and expand new functions).
Today's httpErrorHandler is actually a policy pattern (strategy pattern). HttpErrorHandler uses a unified interface (method) to deal with different error states, and the difference between the policy pattern and the chain of responsibility will be explained again at the end of this article.
The realization of responsibility chain in Chain of Responsibility Pattern
The principle is very simple, that is, all the methods are executed one by one, and each method only does what it needs to do. For example, response400 only executes when the status code is 400, while response401 only handles 401 errors, and other methods are only executed when they should be handled. Everyone does his own job, that is, the chain of responsibility.
And then start to implement it.
Increase judgment
According to the definition of the chain of responsibility, each method must know whether it should deal with the current matter or not, so it is necessary to spread the if judgment originally implemented in httpErrorHandler into each method and make it the responsibility of internal control:
Const response400 = (error) = > {if (error.response.status! = 400) return; console.log ('did you submit something strange?') ;}; const response401 = (error) = > {if (error.response.status! = = 401) return; console.log ('login required!') ;}; const response403 = (error) = > {if (error.response.status! = = 403) return; console.log ('do you want to steal something bad?') ;}; const response404 = (error) = > {if (error.response.status! = = 404) return; console.log ('nothing here';}; const httpErrorHandler = (error) = > {response400 (error); response401 (error); response403 (error); response404 (error);}
After putting the logic of judgment into their respective methods, the code of httpErrorHandler has been streamlined a lot, and all the logic in httpErrorHandler has been removed. Now httpErrorHandler only needs to execute response400 to response404 sequentially, anyway, it should be executed, and only direct return should not be executed.
Achieve a true chain of responsibility
Although all split error handling methods will determine for themselves whether they should do it or not as long as they are refactored to the previous step, if your code is like this, other people who will see httpErrorHandler in the future will only say:
What kind of fairy code is this? API performs all error handling whenever it encounters an error?
Because they don't know that there is judgment in every processing method, maybe you will forget it yourself after a while, because now the httpErrorHandler just seems to go from response400 to response404, even though we know the function is correct, we don't see that the responsibility chain is used at all.
So how on earth does it look like a chain? In fact, you can directly use a number to record all the error handling methods to be executed, and by naming to tell the people who see this code in the future, here is the chain of responsibility:
Const httpErrorHandler = (error) = > {const errorHandlerChain = [response400, response401, response403, response404]; errorHandlerChain.forEach ((errorHandler) = > {errorHandler (error);});}; Optimization execution
In this way, the goal of the chain of responsibility has been achieved, and if you use forEach as in the above code, then when you encounter 400 errors, you don't actually need to execute the following response401 to response404.
So we also need to add some logic to each error handling method, so that each method can judge that if it encounters something that it cannot handle, it will throw out a specified string or Boolean value, and then proceed to execute the next method after receiving it. but if the method can be processed, it ends directly after the processing, and there is no need to continue to run the entire chain.
Const response400 = (error) = > {if (error.response.status! = 400) return 'next'; console.log (' did you submit something strange?') ;}; const response401 = (error) = > {if (error.response.status! = = 401) return 'next'; console.log (' login required!') ;}; const response403 = (error) = > {if (error.response.status! = = 403) return 'next';; console.log (' do you want to steal something bad?') ;}; const response404 = (error) = > {if (error.response.status! = = 404) return 'next';; console.log (' there's nothing here');}
If the execution result of a node in the chain is next, let the following methods continue:
Const httpErrorHandler = (error) = > {const errorHandlerChain = [response400, response401, response403, response404]; for (errorHandler of errorHandlerChain) {const result = errorHandler (error); if (result! = = 'next') break;};}; implementation of encapsulation responsibility chain
Now that the implementation of the chain of responsibility is complete, the logic of determining whether to give the next method (judging result! = = 'next') is exposed, which may lead to the implementation of each chain in the project will be different, and the other chains may be judging nextSuccessor or boolean, so finally, you need to encapsulate the implementation of the chain of responsibility so that everyone on the team can use it and follow the specifications in the project.
The chain of responsibility requires:
The current executor.
The next recipient.
Determine whether the current executor needs to be handed over to the next executor after execution.
So when encapsulated into a class, it should look like this:
Class Chain {constructor (handler) {this.handler = handler; this.successor = null;} setSuccessor (successor) {this.successor = successor; return this;} passRequest (... args) {const result = this.handler (.args); if (result = 'next') {return this.successor & & this.successor.passRequest (.args);} return result;}}
When creating an object with Chain, you need to pass in the current responsibility method and set it to handler, and you can assign the next object in the chain to successor with setSuccessor on the new object, and return the this representing the whole chain in setSuccessor, so that you can directly use setSuccessor to set the next receiver after setSuccessor during operation.
Finally, every object generated through Chain will have a passRequest to perform the current responsibility method, … Arg will turn all the parameters passed into an array, and then give them to handler, that is, the current responsibility method for execution. If the returned result result is next, determine whether sucessor is specified to continue execution. If result is not next, return result directly.
With Chain, the code becomes:
Const httpErrorHandler = (error) = > {const chainRequest400 = new Chain (response400); const chainRequest401 = new Chain (response401); const chainRequest403 = new Chain (response403); const chainRequest404 = new Chain (response404); chainRequest400.setSuccessor (chainRequest401); chainRequest401.setSuccessor (chainRequest403); chainRequest403.setSuccessor (chainRequest404); chainRequest400.passRequest (error);}
At this time, there is a sense of chain, people can continue to make adjustments according to their own needs, or do not have to use classes, because the use of design patterns does not need to be limited to how to implement, as long as there is the intention to express the pattern.
The advantages and disadvantages of the chain of responsibility
Advantages:
It conforms to a single responsibility so that there is only one responsibility in each method.
In line with the principle of open and closed, it is very convenient to expand new responsibilities when the demand increases.
When you use it, you don't need to know who is really dealing with it, reducing a lot of if or switch syntax.
Disadvantages:
Team members need to agree on the chain of responsibility, otherwise it will be strange to see a method inexplicably returning a next.
When something goes wrong, it is difficult to troubleshoot the problem, because you do not know which responsibility it is, and you need to look back from the beginning of the chain.
Even a method that does not require any processing will be executed, because it is in the same chain, the examples in this article are executed synchronously, and if there are asynchronous requests, the execution time may be longer.
Different from the strategy model
I also mentioned the policy pattern earlier, starting with the similarity between the two patterns, that is, both can define an interface (httpErrorHandler) for multiple same behaviors (response400, response401, etc.) without knowing who finally executed it. In the implementation, the strategy pattern is relatively simple.
Because the strategy mode directly uses if or switch to control who should do it, it is more suitable for a radish-to-pit situation. Although in the example, the strategy pattern also does its own thing for the wrong status code, and directly leaves the matter to the next when it is not under its own control, each node in the responsibility chain can still do something first when it is not under its own control, and then hand it over to the next node:
Const response400 = (error) = > {if (error.response.status! = = 400) {/ / do something first Return 'next';} console.log (' did you submit something strange?') ;}
In what scenarios do you use it?
For example, when you leave, you need to go through a signing process: you, your Leader and human resources all need to sign, so the responsibility chain can string the signing process of these three roles into a process, and each person will give it to the following person after signing, and the whole process will not be completed until after the signing of human resources. And if the process is handled through the chain of responsibility, there is a way to be flexible no matter how the process changes or increases later.
The above requirements are beyond the competence of the strategic model.
The above is why the code in web development is getting more and more messy. Have you learned any knowledge or skills? If you want to learn more skills or enrich your knowledge reserve, you are welcome to follow the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.