Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to avoid writing bad if...else statements

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Database >

Share

Shulou(Shulou.com)05/31 Report--

How to avoid writing bad if...else sentences, I believe that many inexperienced people are at a loss about this. Therefore, this paper summarizes the causes and solutions of the problem. Through this article, I hope you can solve this problem.

If...else statements are extremely common in the daily process of writing code. Because of its commonness, many students do not think about its proper use in the current code when writing code. As the project grows, bad if...else statements will be everywhere, resulting in a sharp decline in the maintainability of the project. So in this article, I want to talk to you about how to avoid writing bad if...else statements.

For reasons such as decryption, the sample code below will be excerpted from some open source software or abstract production code as a demonstration.

| | problem code |

When we see a group of if...else, there is usually no reading burden. But when we see code like this:

Private void validate (APICreateSchedulerMessage msg) {if (msg.getType (). Equals ("simple")) {if (msg.getInterval () = = null) {if (msg.getRepeatCount ()! = null) {if (msg.getRepeatCount ()! = 1) {throw new ApiMessageInterceptionException (argerr ("interval must be set when use simple scheduler when repeat more than once")) }} else {throw new ApiMessageInterceptionException (argerr ("interval must be set when use simple scheduler when repeat forever")) }} else if (msg.getInterval ()! = null) {if (msg.getRepeatCount ()! = null) {if (msg.getInterval () 2147454847000L) {throw new ApiMessageInterceptionException (argerr ("stopTime out of mysql timestamp range")) } if (msg.getStartTime () = = null) {throw new ApiMessageInterceptionException (argerr ("startTime must be set when use simple scheduler"));} else if (msg.getStartTime ()! = null & & msg.getStartTime ()

< 0) { throw new ApiMessageInterceptionException(argerr("startTime must be positive integer or 0")); } else if (msg.getStartTime() != null && msg.getStartTime() >

2147454847) {/ / mysql timestamp range is' 1970-01-01 00 UTC 01' UTC to '2038-01-1903 / / we accept 0 as startDate means start from current time throw new ApiMessageInterceptionException (argerr ("startTime out of range"));} if (msg.getRepeatCount ()! = null & & msg.getRepeatCount () 18 & & student.getGender () = = MALE) {result.add (student);}} return result;}

| use design mode |

In addition to the above tips, we can also use design patterns to avoid writing bad if...else statements. In this section, we will mention the following design patterns:

State mode

Mediator mode

Observer mode

Strategy mode

1. State mode

In the code, we often judge the state of some business object to determine what it should do under the current call. For example, we now have a bank interface:

Public interface Bank {/ * * Bank Lock * * / void lock (); / * * Bank unlock * * / void unlock (); / * * alarm * * / void doAlarm ();}

Let's take a look at its implementation class

Public class BankImpl implements Bank {@ Overridepublic void lock () {/ / Save this record} @ Overridepublic void unlock () {if ((BankState.Day = = getCurrentState () {/ / unlock this record normally during the day / / only save this record} else if (BankState.Night = = getCurrentState ()) {/ / unlock this record at night, there may be problems / / save this record and call doAlarm () } @ Overridepublic void doAlarm () {if ((BankState.Day = = getCurrentState () {/ / call the police during the day, contact the local police, and keep this record} else if (BankState.Night = = getCurrentState ()) {/ / report to the police at night, there may be an accident, not only contact the local police, but also need to coordinate nearby security personnel And keep this record}} private BankState getCurrentState () {return BankState.Day }}

Obviously, we are involved in a state:

Public enum BankState {Day,Night}

In different states, banks may react differently to the same thing. This is obviously frustrating, because in a real business scenario, there may be more than two states of the business. Write one more if...else for each one more. So, if you follow the state mode, you can ReFactor it like this:

Public class BankDayImpl implements Bank {@ Overridepublic void lock () {/ / Save this record} @ Overridepublic void unlock () {/ / unlock this record during the day / / just save this record} @ Overridepublic void doAlarm () {/ / call the police during the day, contact the local police, and keep this record}} public class BankNightImpl implements Bank {@ Overridepublic void lock () {/ / Save this record} @ Overridepublic void unlock () {/ / unlocked at night There may be a problem / / save this record and call doAlarm () } @ Overridepublic void doAlarm () {/ / call the police at night, there may be an accident, not only contact the local police, but also need to coordinate the nearby security personnel, and keep this record}} 2. Mediator mode

In the code in the first paragraph of this article, it is actually code somewhere in ZStack 2.0.5, which is used to prevent users from passing in improper parameters when using Cli, causing the later logic to not work properly. In order to make it easy to understand, we can simplify the rules and draw a picture for everyone to understand.

Suppose this is an "archaic" interface that submits scheduled tasks for restarting VM (because good interaction designers don't design the interface like this.). The rules are roughly as follows:

2.1 Scheduler of type Simple

For Scheduler of type Simple, you can customize a task according to Interval,RepeatCount,StartTime.

2.1.1 when selecting a task of type Simple, these two parameters Interval,StartTime are required.

2.1.2 when Interval and StartTime are filled in, scheduled tasks can be submitted at this time

2.1.3 RepeatCount is an optional parameter

2.2 Scheduler of type Cron

Scheduler of type Cron, you can submit tasks based on cron expressions.

2.2.1 when you fill in the cron expression, you are ready to submit scheduled tasks

Here, please think about a question: if you want to write such an interface, how to write it?-- in a windows class, first determine which type the optional column above is, and then decide whether the submit button is lit up according to whether the value in the text box is filled in. This is basic logic. The above has not mentioned the check of boundary values-these check values are often scattered in the instances of various components, and communicate with each other to determine what kind of changes they should make. I believe you have realized the horror of directly mindless if...else code.

2.3 use arbitrators to improve it

Next, we will post some pseudo code to make it easier for readers to better understand this design pattern.

/ * arbitrator member interface * / public interface Colleague {/ * set the arbitrator of a member * * / void setMediator (Mediator mediator); / * set whether the member is enabled * / void setColleagueEnabled (boolean enabled);} / * * arbitrator interface * / public interface Mediator {/ * * call this method * / void colllectValueChanged (String value) when the state of a team member changes Components containing textField should implement the interface * / public interface TextField {String getText ();} / * when the value of a component changes, the ValueListener will be notified * * / public interface ValueListener {/ * when the value of the team member changes, the interface will be called * * / void valueChanged (String str);}

After defining several interfaces, we began to write concrete classes:

CheckBox used to represent Simple and Cron

Public class CheckBox {private boolean state;public boolean isState () {return state;} public void setState (boolean state) {this.state = state;}}

Button

Public class ColleagueButtonField implements Colleague, ValueListener {private Mediator mediator;@Overridepublic void setMediator (Mediator mediator) {this.mediator = mediator;} @ Overridepublic void setColleagueEnabled (boolean enabled) {setEnable (enabled);} private void setEnable (boolean enable) {/ / remove the underscore when true and allow to be pressed} @ Overridepublic void valueChanged (String str) {mediator.colllectValueChanged (str);}}

And several Text.

Public class ColleagueTextField implements Colleague, ValueListener, TextField {private Mediator mediator;private String text;@Overridepublic void setMediator (Mediator mediator) {this.mediator = mediator;} @ Overridepublic void setColleagueEnabled (boolean enabled) {setEnable (enabled);} private void setEnable (boolean enable) {/ / remove the underscore when true and enter the allowed value} @ Overridepublic void valueChanged (String str) {mediator.colllectValueChanged (str);} @ Overridepublic String getText () {return text;}}

The specific implementation of SchedulerValidator SchedulerValidatorImpl will not be posted, there is only some check logic.

Then comes our main class, that is, the window class that knows the global state.

Public class MainWindows implements Mediator {private SchedulerValidator validator = new SchedulerValidatorImpl (); ColleagueButtonField submitButton, cancelButton;ColleagueTextField intervalText, repeatCountText, startTimeText, cronText;CheckBox simpleCheckBox, cronCheckBox;public void main () {createColleagues ();} / * when a team member changes state, call this method * the component initializes with true * / @ Overridepublic void colllectValueChanged (String str) {if (simpleCheckBox.isState ()) {cronText.setColleagueEnabled (false); simpleChanged () } else if (cronCheckBox.isState ()) {intervalText.setColleagueEnabled (false); repeatCountText.setColleagueEnabled (false); startTimeText.setColleagueEnabled (false); cronChanged ();} else {submitButton.setColleagueEnabled (false); intervalText.setColleagueEnabled (false); repeatCountText.setColleagueEnabled (false); startTimeText.setColleagueEnabled (false); cronText.setColleagueEnabled (false) }} private void cronChanged () {if (! validator.validateCronExpress (cronText.getText)) {submitButton.setColleagueEnabled (false);}} private void simpleChanged () {if (! validator.validateIntervalBoundary (intervalText.getText ()) | |! validator.validateRepeatCountBoundary (repeatCountText.getText ()) | |! validator.validateStartTime (startTimeText.getText () {submitButton.setColleagueEnabled (false) }} private void createColleagues () {submitButton = new ColleagueButtonField (); submitButton.setMediator (this); cancelButton = new ColleagueButtonField (); cancelButton.setMediator (this); intervalText = new ColleagueTextField (); intervalText.setMediator (this); repeatCountText = new ColleagueTextField (); repeatCountText.setMediator (this); startTimeText = new ColleagueTextField (); startTimeText.setMediator (this); cronText = new ColleagueTextField (); cronText.setMediator (this); simpleCheckBox = new CheckBox () CronCheckBox = new CheckBox ();}}

In this design pattern, the judgment of the state of all instances is left to the instance of the arbitrator, rather than communicating with each other. In the current scenario, there are not many instances involved, but in a complex system, the instances involved will become very many. Suppose there are now two instances of A _ maeb, then there will be two communication lines:

When there is A _ C, there are six lines.

When there are 4 instances, there will be 12 communication lines

When there are 5 instances, there will be 20 communication lines

And so on.

At this point, the advantages of the arbitrator model come into play-if the logic is scattered among the roles, the code will become difficult to maintain.

3. Observer mode

Design pattern appreciation of ZStack Source Code Analysis-- Troika

Https://segmentfault.com/a/1190000012903365

Combined with the theme of this article, the Observer pattern actually does more to split the if...else into its own modules. In the case of ZStack, for example, when the main storage is reconnected, the main storage module may have to let module An and module B do something. If the observer mode is not used, then the code will be coupled under the main storage module, and it is not possible to disassemble the if...else.

Improve the previous arbitrator example

The Observer pattern generally communicates in an event-driven manner, so Observer and Subject are generally loosely coupled-- Subject does not specify consumers when issuing notifications. In the previous example of the arbitrator pattern, the arbitrator and members are tightly coupled (that is, they must perceive each other), so it can be considered to improve it through the observer pattern.

4. Strategy mode

Usually when programming, the algorithm (policy) will be written in the specific method, which will cause the specific method to be full of conditional judgment statements. But Strategy deliberately separates the algorithm from the rest, only defines the interface, and then uses the algorithm as a delegate. However, this approach makes the program more loosely coupled (because using delegates can easily replace the algorithm as a whole), making the whole project more robust.

After reading the above, do you know how to avoid writing bad if...else statements? If you want to learn more skills or want to know more about it, you are welcome to follow the industry information channel, thank you for reading!

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.

Share To

Database

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report