Открытый закрытый принцип определяет следующим образом
Элементы программного обеспечения (классы, модули, функции…) должны быть открыты для расширения, но закрыты для модификации
😦? ← если вы сейчас так реагируете, продолжайте читать эту статью👍
👎 Плохой код
Это супер маленькое приложение, с помощью которого вы можете узнать, как сказать «Доброе утро» в каждой стране.
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
😅 Как может быть плохой код?
Ну, если вы хотите добавить «Испанию» сейчас, вы бы изменили код следующим образом
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')
]
Это как раз против принципа open-closed, потому что greetingList()
должен быть закрыт, мы не хотим, чтобы он был открыт.
Другими словами, мы не должны модифицировать greetingList()
при добавлении/расширении.
Кто-то даже допускает ошибку при модификации кода.
👍 Хороший код
Так как же мы пишем код?
// 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)
Важной частью хорошего кода является создание класса каждой страны, который зависит от интерфейса ICountry.
Затем, когда вы добавляете «spain», просто вот так ↓
// 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)
Теперь, как вы видите, просто добавьте класс Spain. Вам не нужно изменять greetingList()
, так что вы можете не ошибиться при добавлении страны 👍.
Некоторые люди говорят, что принцип «открыто-закрыто» немного преувеличен, потому что он делает код более сложным, чем плохой код.
На самом деле я тоже так думаю, и это зависит от ситуации.
Но я уверен, что вам важно знать эти знания, помимо того, будете ли вы их использовать или нет.
И я очень рекомендую вам реализовать какой-нибудь код самостоятельно
sayonara👋