Перейти к основному содержимому

Открыт для расширения, закрыт для изменения

Принцип открытости/закрытости гласит: код должен быть открыт для расширения — новое поведение можно добавить, — но закрыт для изменения — существующий, работающий и проверенный код ради этого не правят.

Каждая правка работающего кода — это шанс его сломать. Когда добавление возможности означает только добавление нового кода, старый код остаётся проверенным.

Инструмент TypeScript для этого — интерфейс: функция, которая зависит от интерфейса, никогда не нуждается в изменении, когда её реализует новый класс.


switch, который никогда не перестаёт расти

Этот калькулятор площади использует switch по виду фигуры. Он работает — пока не появится следующая фигура. Треугольник? Правим switch. Пятиугольник? Правим снова. Функция никогда не завершена, и каждая правка ставит под угрозу фигуры, которые уже работали.

switch по виду фигуры

totalArea обязана знать каждый вид фигуры. Добавление одного вида означает изменение этой проверенной функции — ровно то, от чего предостерегает принцип.

Prompt
Напиши программу на TypeScript с функцией totalArea, которая вычисляет суммарную площадь фигур с помощью switch по полю kind (circle и rectangle хранятся в одном типе объекта с width, height и radius). Выведи суммарную площадь нескольких фигур с двумя знаками после запятой — как плохую отправную точку для принципа открытости/закрытости.
Вывод: программа на TypeScript и захваченный вывод

Расширение через интерфейс

Решение: каждая фигура сама знает свою площадь. Интерфейс Shape требует один метод, area(), а totalArea просто складывает всё, что получает, — ей больше неважно, что это за фигуры.

Теперь посмотрите, как работает принцип: совершенно новый класс Triangle подключается, а totalArea не тронута. Расширение без изменения.

Каждая фигура вычисляет свою площадь сама

totalArea зависит только от интерфейса Shape. switch исчез — а вместе с ним и необходимость когда-либо снова править эту функцию.

Prompt
Перепиши фигуры на TypeScript в стиле принципа открытости/закрытости: интерфейс Shape с методом area, отдельные классы Circle и Rectangle, каждый из которых сам вычисляет свою площадь, и функция totalArea, которая суммирует любой массив Shape без switch. Выведи сумму с двумя знаками после запятой.
Вывод: программа на TypeScript и захваченный вывод

Добавьте новую фигуру, ничего не трогая

Triangle — это чистый новый код: класс и его метод area(). totalArea, Circle и Rectangle остались ровно такими, какими были, — открыты для расширения, закрыты для изменения.

Prompt
Расширь пример с интерфейсом Shape в TypeScript совершенно новым классом Triangle, который реализует area, не изменяя ни totalArea, ни Circle, ни Rectangle. Выведи новую сумму вместе с треугольником, чтобы показать расширение без изменения.
Вывод: программа на TypeScript и захваченный вывод
Add a new shape, touch nothing