DEV Community

Kaziu
Kaziu

Posted on • Edited on

SOLID : Open closed principle, explain simply

Open closed principle defines like that

Software elements (classes, modules, function...) should be open for extension, but closed for modification

😦? ← if you react like this now, keep reading this articleπŸ‘

πŸ‘Ž Bad code

This is super small application that you can find how to say "Good morning" in each country

class Country { name: string constructor(name: string) { this.name = name } } const greetingList = (countries: Country[]) => { countries.forEach(country => { switch (country.name) { case 'poland': console.log('dzien dobry') break case 'japan': console.log('ohayo') break case 'usa': console.log('good morning') break default: console.log('* no data *') break } }) } const countries: Country[] = [ new Country('poland'), new Country('japan'), new Country('usa') ] greetingList(countries) // dzien dobry // ohayo // good morning 
Enter fullscreen mode Exit fullscreen mode

πŸ˜… How could be bad code ??

well, if you want to add "spain" now, you would modify code like this

const greetingList = (countries: Country[]) => { countries.forEach(country => { switch (country.name) { case 'poland': console.log('dzien dobry') break case 'japan': console.log('ohayo') break case 'usa': console.log('good morning') break // πŸ‘‡ add this code "spain", this is key code! case 'spain': console.log('buenos dias') break default: console.log('* no data *') break } }) } const countries: Country[] = [ new Country('poland'), new Country('japan'), new Country('usa') // πŸ‘‡ add this code "spain" new Country('spain') ] 
Enter fullscreen mode Exit fullscreen mode

This is exactly anti open-closed principle because greetingList() should be closed, we don't want it to be open.
In other words, we shouldn't modify greetingList() when we add/extension
Someone even makes some mistake while modifying code.

πŸ‘ Good code

So how we write code ??

// create interface interface ICountry{ greeting(): string } // create each country class class Poland implements ICountry { greeting = () => 'dzien dobry' } class Japan implements ICountry { greeting = () => 'ohayo' } class Usa implements ICountry { greeting = () => 'good morning' } const greetingList = (countries: ICountry[]) => { for (let i = 0; i < countries.length; i++) { console.log(countries[i].greeting()) } } const countries: ICountry[] = [ new Poland(), new Japan(), new Usa() ] greetingList(countries) 
Enter fullscreen mode Exit fullscreen mode

Important part of good code is creating each country class which depends on ICountry interface.
Then when you add "spain", just like that ↓

// create interface interface ICountry{ greeting(): string } // create each country class class Poland implements ICountry { greeting = () => 'dzien dobry' } class Japan implements ICountry { greeting = () => 'ohayo' } class Usa implements ICountry { greeting = () => 'good morning' } // πŸ‘‡ add just "Spain class" class Spain implements ICountry { greeting = () => 'Buenos dias' } // ⭐ Don't need to modify this function!  // ⭐ It means greetingList is closed, but for extension, it is opened const greetingList = (countries: ICountry[]) => { for (let i = 0; i < countries.length; i++) { console.log(countries[i].greeting()) } } const countries: ICountry[] = [ new Poland(), new Japan(), new Usa(), new Spain() ] greetingList(countries) 
Enter fullscreen mode Exit fullscreen mode

Now as you see, just add Spain class. You don't need to modify greetingList(), so you might not make some mistake when you add country πŸ‘

(Add) πŸ’Ž React.js

I even tweeted
He wrote it as clean code, but it also resolve opened principle problem 😎


Some people says open-closed principle is a bit exaggerated, because it makes code more complicate than bad code.
Actually I think so too, and it depends on situation.

But I'm sure it's important that you know this knowledge aside from whether you will use it or not.
And I highly recommend you to implement some code by yourself

sayonaraπŸ‘‹

Top comments (0)