Принцип единой ответственности
Перевод: Amr Saeed — Single Responsibility Principle
Если вы увлеченный разработчик, которому интересно научиться писать высококачественные программные решения, то вы попали в нужное место, мой друг.
Один из наиболее распространенных и эффективных принципов разработки программного обеспечения — принципы SOLID, введенные Робертом Мартином, известным как дядя Боб. Они предназначены для того, чтобы сделать программное обеспечение более понятным, гибким и легко поддерживаемым.
SOLID — это аббревиатура от 5 принципов проектирования:
- Single responsibility. (Принцип единой ответственности)
- Open-closed. (Принцип открытости/закрытости)
- Liskov substitution. (Принцип подстановки Лисков)
- Interface segregation. (Принцип разделения интерфейса)
- Dependency inversion. (Принцип инверсии зависимостей)
В этой статье мы поговорим о первом и самом простом из них — Single Responsibility (Принцип единой ответственности).
Принцип единственной ответственности гласит:
“У класса должна быть только одна причина для изменения”
Но что означает фраза «только одна причина»!
Вы знаете, я считаю, что примеры — лучший учитель. Давайте рассмотрим следующий фрагмент кода, чтобы понять.
class MusicPlayer{ void playMusic(){ System.out.println("Let the fun begins!"); } void openPhoto(){ System.out.println("Really! should I open the photo now?"); } }
Как видите, у нас есть класс музыкального проигрывателя, который может воспроизводить музыку и открывать фотографии.
Попробуйте представить, что этот класс существует в каком-то проекте в компании XYZ, на которую вы работаете. Халед работает фотографом в XYZ и использует функцию openPhoto для открытия фотографий. Али — еще один сотрудник, который увлекается музыкой и использует функцию воспроизведения музыки playMusic.
Если Халед попросил вам изменить способ открытия фотографий, то вам нужно изменить класс MusicPlayer и изменить в нем функцию openPhoto. Точно так же, если бы Али попросил вас сделаете то же самое, но с функцией playMusic.
Мы дали классу две разные причины измениться, и они не связаны друг с другом. Один для музыки, другой для фотографий. Кроме того, какая связь между классом MusicPlayer и функцией openPhoto! Очевидно, что openPhoto здесь не должно быть.
Класс выглядит как студент, который работает на двух совершенно разных работах. В программной инженерии это плохая практика. Чем больше класс может делать что-то, тем больше он подвержен изменениям, следовательно, больше ошибок и проблем.
Более того, попробуйте представить, решили ли мы удалить несколько строк кода из playMusic, но обнаружили, что openPhoto сломался. Разные вещи в одном месте могут влиять друг на друга. Таким образом везде могут появится баги дружище, везде!
Итак, давайте разделим обязанности и дадим классу одну причину для изменений.
class MusicPlayer{ void playMusic(){ System.out.println("Let the fun begins!"); } } class PhotoViewer{ void openPhoto(){ System.out.println("What about now should I open it?"); } }
Теперь, если мы решили изменить функциональность фотографий в любое время, мы не будем трогать функциональность музыки, и наоборот. Кроме того, известно, что функции логически связаны с именами их классов.
На практике очень сложно дать классу только одну причину для изменения, поскольку существует множество функций, но вы можете сделать так, чтобы его функции были связаны настолько, насколько это возможно. В программной инженерии это обычно называется сплоченностью (cohesion). Классы с высокой степенью сплоченности — показатель хорошего дизайна.
Вы можете применить принцип единой ответственности также к функциям. Функция должна выполнять одну конкретную задачу, ни больше ни меньше.
Когда вы пишете функцию, всегда спрашивайте себя, что она делает? если вы говорите, что она делает что-то «и» что-то. Наличие здесь «и» означит, что вы делаете что то неправильно.
На этом это статья заканчивается.
В следующей статье мы обсудим принцип «открытости/закрытости».