Writing in the front

The more conditional logic becomes larger, the more complex the program becomes, and the more understandable it becomes to reconstruct conditional logic. When the conditional logic is split and merged, the conditional logic can be simplified and the code logic becomes clearer and easier to understand.

Previously on:

  • Refactoring, Tasteful Code 01 — On the Road to Refactoring
  • Refactoring, Tasteful Code 02 — Building test Systems
  • Refactoring, Tasteful Code 03 — Common Refactoring Techniques
  • Refactoring, Tasteful Code 04 — Encapsulation
  • Refactoring, Tasteful Code 05 — Moving Features
  • Refactoring, Tasteful Code 06 — Reorganizing Data

Reduced conditional logic

Common ways to simplify conditional logic are:

  • Decomposition conditional expression
  • Merge conditional expression
  • Replace nested conditional expressions with a guard statement
  • Replace conditional expressions with polymorphism
  • The introduction of special case
  • Introduction of assertions

1. Decompose conditional expressions

In programming, complex conditional logic can lead to increased algorithm complexity because different things can be done according to different conditional branches, resulting in complex and lengthy functions. As you know, the larger and longer the function, the less readable the code becomes, and the more difficult it becomes to understand and read.

In the previous articles, large functions can be decomposed into smaller functions based on functional intent, so conditional logic functions can be decomposed according to the intent of logical branching.

Original code:

if(! have.before(plan.summerStart) && ! plan.after(plan.summerEnd)){ charge = quantity * plan.summerRate; }else{
  charge = quantity * plan.regularRate + plan.regularServiceCharge;
}
Copy the code

Refactoring code:

charge = summer() ? summerCharge() : regularCharge();

function summer(){
  return! have.before(plan.summerStart()) && ! have.aftet(plan.summerEnd()); }function summerCharge(){
  return quantity * plan.summerRate;
}

function regularCharge(){
  return quantity * plan.regularRate + plan.regularServiceCharge;
}
Copy the code

2. Merge conditional expressions

The code is being checked for conditions that differ, but the behavior of handling events is the same. Instead of using conditional logic to process events, you can use logic “or” and “to merge them into conditional expressions and break up verbose function code. Using conditional expressions can make code reading clearer, and refining functions can refine the code logic of conditional functions into independent functions, which can clarify the code meaning.

Specifically, when merging conditional expressions, we must first determine whether they have side effects, and separate the query function from the modification function. Combine two logical conditional expressions into one, using the appropriate logical operators.

Original code:

if(employee.seniority < 2) return 0;
if(employee.months > 12) return 0;
if(employee.time) return 0;
Copy the code

Refactoring code:

function func(){
  return (employee.seniority < 2) || (employee.months > 12) || employee.time)
}

if(func()) return 0;
Copy the code

3. Replace nested conditional expressions with nested statements

There are two common styles in conditional expressions: both conditional branches are normal behavior, and you can use if… else… ; Normal behavior when there is only one conditional branch, and abnormal behavior when there is an unusual condition that should be checked separately (this is the “guard statement”) and returned immediately from the function if the condition is true.

By replacing nested conditional expressions with “guard statements”, special attention is given to one branch of them. Instead of treating the conditional statements equally, we rely on the most important branch statements, so that the reader can see through the logic at a glance.

Original code:

function payMount(){
  let result;
  if(isDead){
    result = amountFunc();
  }else{
    if(isSeparated){
      result = separatedAmout();
    }else{
      if(isRetired){
        result = retiredAmount()
      }else{ result = normalAmount(); }}}return result;
}
Copy the code

Refactoring code:

function payMount(){
  if(isDead) result = amountFunc();
  if(isSeparated) result = separatedAmout();
  if(isRetired) result = retiredAmount();
  return normalAmount();
}
Copy the code

4. Replace conditional expressions with polymorphism

In programming complex conditional logic is rather difficult to understand code, and rather than seeking to add structure to conditional logic, it is better to split and branch conditions into different scenarios, namely, higher-order use cases. When disassembling complex conditional logic, it is sometimes found that the structure of conditional logic is sufficient to express it, but it can be expressed more clearly by using classes and polymorphisms.

If an existing class does not already have polymorphic behavior, you can create a factory function that returns the appropriate object instance, which can be retrieved when the method is called. A conditional function can be moved into a superclass if the conditional logic has not been distilled to a separate function. Optionally subclass creates a function, overwrites the function that holds the conditional expression in the superclass, and copies the subclass related conditional expression branch to the new function for adjustment.

Original code:

switch(user.type){
  case "UserName":
    return "yichuan";
  case "UserAge":
    return this.age > 18 ? "Adult" : "Minor";
  case "UserUniversity":
    return this.score > 600 ? "985 university" : "Non-985 colleges and Universities";
  default:
    return "unknown";
}
Copy the code

Refactoring code:

class UserName{
  get detail() {return "yichuan"; }}class UserAge{
  get detail() {return this.age > 18 ? "Adult" : "Minor"; }}class UserUniversity{
  get detail() {return this.score > 600 ? "985 university" : "Non-985 colleges and Universities"; }}Copy the code

5. Introduce exceptions

A common example of repetitive code is that the users of a data structure are all checking for a particular value and doing the same when that particular value is present. If you find that your code handles the same particular value in the same way multiple times, you can integrate the processing logic.

The best way to deal with duplicate code is to use the “special case” pattern, where you create a special case element that handles the common behavior of the special cases and replace part of the special case checking logic with a function call.

In general, special cases can take several forms, and we can deal with common ways. Such as:

  • Reading data only from an object can provide a literal object prefilled with values
  • If you need more than simple values, you can create functions that correspond to all the common behaviors of the guarantee
  • A special case object can be wrapped as a class and returned, or it can be transformed into a data structure
// The original code
if(flag === "unkown") name = "yichuan";

// Refactor code
class User{
  get name() {return "yichuan"; }}Copy the code

6. Introduce assertions

In program development, the code works only if a condition is true, and it is common practice to use comments to explain it. The use of assertions makes assumptions explicit, since a conditional expression should always be identical to truth, and the failure of assertions should not be caught anywhere in the system.

Assertions are highly valuable for communication and can resolve errors that are currently being traced, but self-testing code reduces the value of assertions during debugging because unit tests that progressively approach often help with debugging.

Original code:

func(num){
  return (discountRate) ? num - (discountRate * num) : num;
}
Copy the code

Refactoring code:

set discountRate(num){
  assert(null === num || num >= 0);
  discountRate= num;  
}
Copy the code

summary

In this article, I’ve shown you how to simplify conditional logic so that you can manipulate it and make your code clearer and easier to understand.

Refer to the article

Refactoring — Improving the Design of Existing Code (2nd edition)

Write in the last

Thank you for reading, I will continue to share with you more excellent articles, this article reference a large number of books and articles, if there are mistakes and mistakes, hope to correct.

More latest articles please pay attention to the author nuggets a sichuan firefly account and the public number front gravitation.