The open-closed principle states that classes, modules, and functions should be open for extension but closed for modification.
This principle might seem to contradict itself, but you can still make sense of it in code.
It means you should be able to extend the functionality of a class, module, or function by adding more code without modifying the existing code.
Here’s some code that violates the open-closed principle in JavaScript:
classAnimal {constructor(name, age, type) {this.name = name;this.age = age;this.type = type; }getSpeed() {switch (this.type) {case'cheetah':console.log('Cheetah runs up to 130mph ');break;case'lion':console.log('Lion runs up to 80mph');break;case'elephant':console.log('Elephant runs up to 40mph');break;default:thrownewError(`Unsupported animal type: ${this.type}`); } }}constanimal1=newAnimal('Lion',4,'lion');animal1.getSpeed(); // Lion runs up to 80mph
The code above violates the open-closed principle because if you want to add a new animal type, you have to modify the existing code by adding another case to the switch statement.
Normally, if you’re using a switch statement, then it’s very likely you will violate the open-closed principle.
Here’s how I refactored the code to fix the problem:
classAnimal {constructor(name, age, speedRate) {this.name = name;this.age = age;this.speedRate = speedRate; }getSpeed() {returnthis.speedRate.getSpeed(); }}classSpeedRate {getSpeed() {}}classCheetahSpeedRateextendsSpeedRate {getSpeed() {return130; }}classLionSpeedRateextendsSpeedRate {getSpeed() {return80; }}classElephantSpeedRateextendsSpeedRate {getSpeed() {return40; }}constcheetah=newAnimal('Cheetah',4,newCheetahSpeedRate());console.log(`${cheetah.name} runs up to ${cheetah.getSpeed()} mph`); // Cheetah runs up to 130 mphconstlion=newAnimal('Lion',5,newLionSpeedRate());console.log(`${lion.name} runs up to ${lion.getSpeed()} mph`); // Lion runs up to 80 mphconstelephant=newAnimal('Elephant',10,newElephantSpeedRate());console.log(`${elephant.name} runs up to ${elephant.getSpeed()} mph`); // Elephant runs up to 40 mph
This way, if you want to add a new animal type, you can create a new class that extends SpeedRate and pass it to the Animal constructor without modifying the existing code.
For example, I added a new GoatSpeedRate class like this:
classGoatSpeedRateextendsSpeedRate {getSpeed() {return35; }}// Goatconstgoat=newAnimal('Goat',5,newGoatSpeedRate());console.log(`${goat.name} runs up to ${goat.getSpeed()} mph`); // Goat runs up to 354 mph