Snow the bunny.

What is the Open-Closed Principle?

Let’s look at the Open-Closed Principle in object-oriented programming and how can it help you develop better applications and software.

Making cats, dogs and rabbits

Yesterday I wrote about the Single Responsibility Principle and how to use it to code better dogs.

Imagine I’ve created an Animal class with a few methods for most animals do, such as sleep and making sounds.

class Animal {
  constructor(type, color) {
    this.type = type;
    this.color = color;
  }

  sleep() {
    console.log(`The ${this.color} ${this.type} is sleepy.`);
    setTimeout(() => {
      console.log(`The ${this.color} ${this.type} took a nap.`);
    }, 3000);
  }

  makeSound() {
    console.log(`The ${this.color} ${this.type} made a sound.`);
  }
}

Now that I’ve created this Animal class, I can create some child classes that will inherit its methods and properties.

class Cat extends Animal {
  constructor(color) {
    super("cat", color);
  }
}

class Dog extends Animal {
  constructor(color) {
    super("dog", color);
  }
}

class Rabbit extends Animal {
  constructor(color) {
    super("rabbit", color);
  }
}

Finally I can create instances of the Cat, Dog and Rabbit classes.

const cat = new Cat("orange");
const dog = new Dog("black");
const rabbit = new Rabbit("white");

So far so good. If I want either the cat, dog, or rabbit to sleep or make a sound, I can just call either the makeSound or sleep methods.

Animals don’t make the same sounds

Currently, the makeSound method only allows me to “make a sound.” But in real life, most cats meow, most dogs bark, and most rabbits don’t make a sound at all. So this method isn’t really doing what I want it to do.

I could fix this by adding a conditional statement to the makeSound method like this:

makeSound() {
  if (this.type === "cat") {
    console.log(`The ${this.color} ${this.type} said meow.`);
  } else if (this.type === "dog") {
    console.log(`The ${this.color} ${this.type} said woof.`);
  }
}

Now if the animal is a “cat” type, it will meow, but if it’s a “dog” type, it will woof.

Notice I didn’t put a condition for a “rabbit” type. Also, what if I want to create more animal types like kangaroos, orangutans, and horses? Am I going to have to make a condition for each type?

Open-Closed Principle

According to Wikipedia’s definition of the Open-Closed Principle, software entities such as classes and functions “should be open for extension, but closed for modification”.

What does that mean? It’s a bit tricky to explain in abstract terms, but looking at the classes we currently have, I think we’re trying to modify the parent Animal class with the makeSound method, when we should rather just extend the Animal class with specific methods for making a sound.

Let’s refactor our current classes to fix this.

Refactoring to support the Open-Closed Principle

So here’s a new Animal class:

class Animal {
  constructor(type, color) {
    this.type = type;
    this.color = color;
  }

  sleep() {
    console.log(`The ${this.color} ${this.type} is sleepy.`);
    setTimeout(() => {
      console.log(`The ${this.color} ${this.type} took a nap.`);
    }, 3000);
  }

  sniff() {
    console.log(`The ${this.color} ${this.type} sniffed.`);
  }
}

There now is no makeSound method. But I have added a sniff method, since most animals sniff the same.

And the updated Cat, Dog and Rabbit classes:

class Cat extends Animal {
  constructor(color) {
    super("cat", color);
  }

  meow() {
    console.log(`The ${this.color} cat said meow.`);
  }
}

class Dog extends Animal {
  constructor(color) {
    super("dog", color);
  }

  bark() {
    console.log(`The ${this.color} ${this.type} said woof.`);
  }
}

class Rabbit extends Animal {
  constructor(color) {
    super("rabbit", color);
  }
}

const cat = new Cat("orange");
const dog = new Dog("black");
const rabbit = new Rabbit("white");

cat.meow();
dog.bark();
rabbit.sniff();
cat.sleep();
dog.sleep();
rabbit.sleep();

So now, instead of attempting to call the makeSound method, each animal has a method specific to the sound it makes. Cats meow. Dogs bark. And rabbits don’t make any sounds, except maybe squeak if you accidentally step of them.


Discover more from AaronTweeton.com

Subscribe to get the latest posts sent to your email.