JavaScript Refactoring —More Class Refactoring

John Au-Yeung - Jan 25 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

We can clean up our JavaScript code so that we can work with them more easily.

In this article, we’ll look at some refactoring ideas that are relevant for cleaning up JavaScript conditionals.

Replace Inheritance with Delegation

If we have subclasses that don’t need to inherit anything from a superclass, then the subclass doesn’t have to be a subclass of the superclass.

For instance, if we have a subclass that doesn’t need anything from the superclass other than calling some methods from it:

class Animal {
  //...
  speak() {
    //...
  }
}

class Cat extends Animal {
  //...
  talk() {
    super.speak()
  }
}
Enter fullscreen mode Exit fullscreen mode

We can remove the extends and just call the Animal class as follows:

class Animal {
  //...
  speak() {
    //...
  }
}

class Cat {
  constructor() {
    this.animal = new Animal();
  }

  talk() {
    this.animal.speak()
  }
}
Enter fullscreen mode Exit fullscreen mode

Reduce Inheritance Hierarchy

We can reduce the inheritance hierarchy to only be what’s necessary.

We don’t want a complex inheritance tree that’s hard to navigate.

For example, if we have the following code:

class Animal {
  //...
}

class Cat extends Animal {

}

class Dog extends Animal {

}

class BlackCat extends Cat {

}

class Labrador extends Dog {

}
Enter fullscreen mode Exit fullscreen mode

Then we may have to rethink if we want to create subclasses for each type of cat and dog.

We can just reduce the tree size by eliminating those classes. For example, we can remove the last 2 classes in the code above by writing:

class Animal {
  //...
}

class Cat extends Animal {

}

class Dog extends Animal {

}
Enter fullscreen mode Exit fullscreen mode

Then the inheritance tree is much less complex.

Convert Procedural Design to Function

If we have lots of procedures doing similar things, we can turn the procedures into functions so we can use them in multiple places.

For instance, if we have the following code:

const subtotal = 100
const provincialSalesTax = subtotal * 0.05;
const federalSalesTax = subtotal * 0.1;
const total = subtotal + provincialSalesTax + federalSalesTax;
Enter fullscreen mode Exit fullscreen mode

We can move the tax calculation code into their own function as follows:

const calculateTax = (amount, taxRate) => amount * taxRate;
const subtotal = 100
const provincialSalesTax = calculateTax(subtotal, 0.05);
const federalSalesTax = calculateTax(subtotal, 0.1);
const total = subtotal + provincialSalesTax + federalSalesTax;
Enter fullscreen mode Exit fullscreen mode

Now if we have to calculate tax amounts again, we can use the calculateTax function instead of writing out the code every time to calculate those amounts.

Extract Hierarchy

If we have class that’s doing too much because of lots of conditional statements in the methods, we can extract those pieces of code into subclasses.

For instance, instead of writing the following:

class Invoice {
  getInvoice(type) {
    if (type === 'residental') {
      //...
    } else if (type === 'commercial') {
      //...
    } else if (type === 'concession') {
      //...
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

We can break the getInvoice logic into their own subclasses as follows:

class Invoice {

}

class ResidentialInvoice extends Invoice {
  getInvoice() {
    // residential logic
  }
}

class CommercialInvoice extends Invoice {
  getInvoice() {
    // commercial logic
  }
}

class ConcessionInvoice extends Invoice {
  getInvoice() {
    // concession logic
  }
}
Enter fullscreen mode Exit fullscreen mode

Assuming the getInvoice method bodies are different in each subclass, the getInvoice method can stay there since they’re all different except for the name.

Conclusion

We can make our code clearer by breaking up complex logic into subclasses.

Also, inherit might not be needed if a class doesn’t need to inherit it.

Reducing the inheritance hierarchy is also a good idea since complexity is bad.

If we have similar logic in different places, we should extract them a function.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .