Javascript skills from ifelse to switchcase to abstract _ javascript

Source: Internet
Author: User
Tags switch case
What do you think is the most impatient to see when you take over the legacy code? Complex UML? I don't think so. My answer is: if of more than two else, or switch of more than two cases. But is it normal to use if else and switch case in a lot of code? Error! If else and switch case with more than two branches should not be hard-coded.
Where does a complex branch come from?
The first question we need to discuss is why there are often so many complicated branches in the legacy code. These complex branches often do not exist in the first version of the Code. If the designer is still somewhat experienced, he should anticipate where expansion may be required in the future, and reserved abstract interfaces.

However, after the code has been iterated by several versions, especially after several requirements and details are adjusted, the complex branch will appear. The detailed adjustment of requirements is often not reflected in UML, but directly reflected in code. For example, the original message is divided into two types: chat message and system message. This is designed as two sub-classes of message class. However, one day the requirements were adjusted. Some of the system messages were important and their titles should be displayed in red. At this time, programmers often make the following changes:
Add an important attribute to the system message class.
Add a branch about the important attribute to the render method to control the title Color.
Why do programmers make such changes? It is possible that he didn't realize that he should abstract it. Because the requirement is that "some of the system messages are important", for programmers who have received more imperative programming language training, perhaps the first thing he thinks of is a flag. A flag can distinguish between important and unimportant. He did not expect this requirement to be explained in another way. "system messages are classified into two categories: Important and unimportant 」. In this way, he knows that the system message should be abstracted.
Of course, it is also possible that the programmer knows it can be abstract, but for some reason, he chooses not to do so. A common situation is that someone forces programmers to sacrifice code quality in exchange for project progress speed-adding an attribute and a branch is much simpler than abstract refactoring, if we want to make 10 modifications in this form, is it faster to make 10 branches or 10 abstractions? The difference is obvious.
Of course, if else is too large, some smart people will come up and say, "Let's change to switch case. In some cases, this can indeed improve code readability, assuming that each branch is mutually exclusive. However, when the number of switch cases increases, the Code becomes unreadable.
What are the disadvantages of complex branches?
What are the disadvantages of complex branches? Let me extract an example from the old Code of Baidu Hi web edition.

The Code is as follows:


Switch (json. result ){
Case "OK ":
Switch (json. command ){
Case "message ":
Case "systemmessage ":
If (json. content. from = ""
& Json. content. content = "kicked "){
/* Disconnect */
} Else if (json. command = "systemmessage"
| Json. content. type = "sysmsg "){
/* Render system message */
} Else {
/* Render chat message */
}
Break;
}
Break;


This code is not difficult to understand, so I asked a simple question: Which of the following branches is hit by the JSON:

The Code is as follows:


{
"Result": "OK ",
"Command": "message ",
"Content ":{
"From": "CatChen ",
"Content": "Hello! "
}
}


You can easily get the correct answer: This JSON hit/* render chat message */(display chat messages) this branch. So how did you make this decision? First, you should check whether it hits case "OK": Branch, and the result is hit; then, you should check whether it hits case "message": Branch, and the result is hit, so case "systemmessage": You don't need to read it. Next, it does not hit the conditions in if, and it does not hit the conditions in else if, therefore, it hits the else branch.
See the problem? Why can't you say this JSON hit this branch when you look at this else? Because else itself does not contain any conditions, it only implies conditions! The condition of each else is the result of the first non-back and operation on each of the previous if and else if statements. That is to say, judging the else hit is equivalent to determining the hit of such a complex set of conditions:

The Code is as follows:


! (Json. content. from = "" & json. content. content = "kicked ")&&! (Json. command = "systemmessage" | json. content. type = "sysmsg ")


Put two switch cases on the outer layer. The condition for this branch is as follows:

The Code is as follows:


Json. result = "OK" & (json. command = "message" | json. command = "systemmessage ")&&! (Json. content. from = "" & json. content. content = "kicked ")&&! (Json. command = "systemmessage" | json. content. type = "sysmsg ")


Here there is a duplicate logic, which is omitted in this way:

The Code is as follows:


Json. result = "OK" & json. command = "message "&&! (Json. content. from = "" & json. content. content = "kicked ")&&! (Json. content. type = "sysmsg ")


How much effort have we made to derive such a long string of logical operation expressions from the four simple else letters? Besides, I can't really understand what this expression is about without looking at it carefully.
This is where it is difficult to read and manage complex branches. Imagine you have a switch case and an if else. There are 3 cases in total, and each case has 3 else, which is enough for your research-every branch, the results of the first-not-last-sum operation of all the front branches and the front branches of all the original branches are hidden in the condition.
How to avoid complicated branches
First, complex logic operations cannot be avoided. The reconstruction result should be equivalent logic. All we can do is to make the code easier to read and manage. Therefore, we should focus on how to make complex logical operations easy to read and manage.
Abstract As a class or factory
For those who are used to object-oriented design, this may mean dividing complex logic operations and distributing them into different classes:

The Code is as follows:


Switch (json. result ){
Case "OK ":
Var factory = commandFactories. getFactory (json. command );
Var command = factory. buildCommand (json );
Command.exe cute ();
Break;
}


This looks good. At least the branch gets shorter and the code gets easier to read. This switch case only involves the branch of the status code. for how to deal with the "OK" status code, this is a matter of other class management. There may be a group of branches in getFactory, focusing on the selection of the factory to which this command should be created. At the same time, buildCommand may have other trivial branches that decide how to build this command.
The advantage of doing so is that the nested relationship between branches is removed, and each branch can be kept correct in its own context. For example, getFactory is now a named function. Therefore, the branch in this function only needs to implement the contract implied by the getFactory name. You do not need to pay attention to the context of actually calling getFactory.
Abstracted as pattern matching
Another approach is to repeat this complex logic operation as pattern matching:

The Code is as follows:


Network. listen ({
"Result": "OK ",
"Command": "message ",
"Content": {"from": "", "content": "kicked "}
}, Function (json) {/* disconnect */});
Network. listen ([{
"Result": "OK ",
"Command": "message ",
"Content": {"type": "sysmsg "}
},{
"Result": "OK ",
"Command": "systemmessage"
}], Function (json) {/* render system message */});
Network. listen ({
"Result": "OK ",
"Command": "message ",
"Content": {"from $ ne": "", "type $ ne": "sysmsg "}
}, Func tion (json) {/* render chat message */});


Is it much clearer now? The first case is to be kicked off and must match the specified from and content values. The second case is to display system messages. Because the system messages are slightly different in the two versions of the protocol, we need to capture two different JSON messages. Matching any one of them is a hit. The third scenario is to display chat messages. in earlier versions, both system messages and offline commands belong to special chat messages. To be compatible with earlier versions, the two cases need to be excluded from the display chat message, so the suffix "$ ne" (not equal) is used for matching.
Since the listen method is context-independent, each listen independently declares what JSON they match, so there is no implicit logic. For example, to capture chat messages, you must explicitly declare and exclude the from = "" And type = "sysmsg" situations, this does not need to be inferred from the context if else.
Pattern Matching greatly improves code readability and maintainability. Because we want to capture JSON, we use JSON to describe what each branch needs to capture, which is much clearer than a long logic expression. At the same time, every modification in this JSON is independent. modifying a condition does not affect other conditions.
Finally, how to compile a pattern matching module is beyond the scope of this article.
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.