Skip to Content
НачалоПринцип единой ответственности

Принцип единой ответственности

Далее: SRP (single-responsibility principle)

Начнём с самого простого и одновременно самого часто нарушаемого принципа.

Принцип единственной ответственности звучит так:

У сущности должна быть только одна причина для изменения.

Звучит просто, да? Но на практике мы постоянно пишем классы, которые делают всё и сразу. А потом удивляемся, почему так сложно что-то поменять.


Пример из жизни

Представь, что ты работаешь в офисе. Твоя задача — писать код. Но вдруг начальник говорит:

Слушай, а можешь ещё и документы подписывать, кофе всем носить, и заодно презентации делать?

Ты бы, наверное, офигел. Потому что это не твоя зона ответственности. Ты — программист, а не бариста и не секретарь. У тебя одна работа, за которую ты отвечаешь.

Так же и с классами.

Плохой пример

Вот класс, который нарушает SRP:

export class UserService { public getUser(id: number) { /* ... */ } public updateUser(id: number, data: any) { /* ... */ } public sendWelcomeEmail(email: string) { /* ... */ } public sendNotification(email: string, message: string) { /* ... */ } public logToFile(message: string) { /* ... */ } public logToDatabase(message: string) { /* ... */ } }

Что здесь не так? Всё! Этот класс:

  • Управляет пользователями
  • Отправляет письма
  • Пишет логи

У него три причины для изменения. Если поменяется логика отправки писем — мы трогаем UserService. Если поменяется формат логов — опять трогаем этот же класс. И так по кругу.

Такой класс быстро превращается в “свалку” методов. Его невозможно тестировать, сложно читать, а уж поддерживать — просто кошмар.

Хороший пример

Разделим ответственность по разным классам:

export class UserService { public getUser(id: number) { /* ... */ } public updateUser(id: number, data: any) { /* ... */ } } export class EmailService { public sendWelcomeEmail(email: string) { /* ... */ } public sendNotification(email: string, message: string) { /* ... */ } } export class LoggerService { public logToFile(message: string) { /* ... */ } public logToDatabase(message: string) { /* ... */ } }

Теперь:

  • Хочешь поменять логику писем? Иди в EmailService.
  • Нужно добавить новый способ логирования? Добро пожаловать в LoggerService.
  • Что-то с пользователями? Работаем только с UserService.

У каждого класса — одна ответственность, одна причина для изменения.

Как понять, что ты нарушаешь SRP?

Задай себе простой вопрос:

Если я изменю это место, сколько всего другого мне придётся перепроверить?

Если больше одного модуля — скорее всего, ты нарушил SRP.

Ещё один признак: если ты не можешь описать, что делает класс, одним предложением без “и”, “а также”, “к тому же” — это звоночек.

“Этот класс управляет пользователями, и отправляет письма, и логирует”

“Этот класс управляет пользователями”

Итог

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

На первый взгляд кажется, что больше классов = больше кода = сложнее. Но на практике наоборот: код становится проще, понятнее и надёжнее.

Last updated on