В первой части статьи мы разбирали что означает буква «S» в данной аббревиатуре. Сейчас мы разберем что означает «O» — это «Open Closed Principe» (или «OCP»), что переводится как Принцип открытости-закрытости. Что это значит? Это значит что класс должен открыт для расширения, но закрыт для модификации.
Как следовать принципу OCP
Следуя данному принципу программные компоненты нужно спроектировать таким образом, чтобы их можно было расширять новым функционалом, не меняя исходный код. Так как изменения при добавлении нового кода могут сломать уже работающую логику.
Чтобы следовать этому принципу нам помогут абстракции, интерфейсы и наследование. Это позволит добавить новый функционал через расширение, а не модификацию существующего кода.
Пример нарушения принципа:
Допустим, есть игровой персонаж — рыцарь:
class Character
{
public function displayInfo() { echo 'Я Рыцарь'; }
}
Мы добавляем возможность играть еще и за волшебника:
class Character
{
public function displayInfo(string $type)
{
if (type == 'Knight') echo 'Я Рыцарь';
if (type == 'Wizard') echo 'Я Маг';
}
}
Что плохо?
- При добавлении персонажа приходится добавлять все больше условий. При наличии 1000 персонажей это будет работать медленно.
- Класс начинает обладать функционалом, который, может, и не нужен. У мага может быть набор заклинаний, у рыцаря его нет.
- Каждое изменение в основном коде может потребовать изменения во всех зависимых частях кода. Например, придется везде менять меч на посох, меняя написанную логику. Это увеличивает риск ошибок и усложняет процесс добавления изменения.
- Существующий код уже написан, оттестирован, одобрен. Его изменение может вызвать много лишних проблем. Лучше не трогать то, что уже работает.
Исправленный код:
Нужно разработать класс так, чтобы новых персонажей можно было добавлять, не редактируя существующий код. Один из вариантов решения:
interface Character { public function displayInfo(); }
class Knight implements Character
{
public function displayInfo()
{
echo 'Я Рыцарь';
}
}
class Wizard implements Character
{
public function displayInfo()
{
echo 'Я Маг';
}
}
$character = new Knight();
$character->displayInfo(); // Я Рыцарь
$character = new Wizard();
$character->displayInfo(); // Я Маг