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()
}
}
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()
}
}
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 {
}
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 {
}
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;
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;
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') {
//...
}
}
}
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
}
}
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.