В объектно-ориентированном программировании принцип единственной обязанности (англ. Single responsibility principle) обозначает, что каждый объект должен иметь одну обязанность и эта обязанность должна быть полностью инкапсулирована в класс. Все его сервисы должны быть направлены исключительно на обеспечение этой обязанности.
Термин был введён Робертом С. Мартином в одноименной статье как часть его Принципов объектно-ориентированного проектирования, ставших популярными благодаря его книге Быстрая разработка программ. Принципы, примеры, практика. Мартин описал её как основанную на принципе связности, сформулированном Томом ДеМарко в его книге Structured Analysis and Systems Specification.
Мартин определяет обязанность как причину изменения и заключает, что класс или модуль должны иметь одну и только одну причину измениться. Объединение двух сущностей, изменяющихся по разным причинам и в разное время, считается плохим проектным решением.
Причина, почему нужно сохранять направленность класса на единственную цель в том, что это делает класс более здоровым.
Например, у нас есть несколько фигур и мы хотели бы суммировать все площади. Ну это довольно просто не так ли?
class Circle { public $radius; public function __construct($radius) { $this->radius = $radius; } } class Square { public $length; public function __construct($length) { $this->length = $length; } }
Во-первых, мы создаем классы для наших фигур и в конструкторах устанавливаем нужные параметры. Затем мы создаем класс AreaCalculator и описываем в нем логику суммирования площадей фигур.
class AreaCalculator { protected $shapes; public function __construct($shapes = array()) { $this->shapes = $shapes; } public function sum() { // logic to sum the areas } public function output() { return implode('', array( "<h1>", "Sum of the areas of provided shapes: ", $this->sum(), "</h1>" )); } }
Для использования класса AreaCalculator мы создаем простой объект, передаем в него массив с фигурами и выводим результат вычислений.
$shapes = array( new Circle(2), new Square(5), new Square(6) ); $areas = new AreaCalculator($shapes); echo $areas->output();
Проблема с методом вывода в том, что класс AreaCalculator реализует всю логику вывода в нем. Но что будет, если пользователь захочет вывести данные в формате JSON?
Вся логика по рассчету и выводу хранится в одном классе - это то, с чем борется принцип SPR. Класс AreaCalculator должен отвечать за вычисления суммы площадей (о чем говорит название класса), но не за вывод результатов в формате HTML.
Чтобы в полной мере реализовать принцип, нам нужно создать другой класс SumCalculatorOutputter, который будет заниматься выводом результатов.
Класс SumCalculatorOutputter будет работать следующим образом:
$shapes = array( new Circle(2), new Square(5), new Square(6) ); $areas = new AreaCalculator($shapes); $output = new SumCalculatorOutputter($areas); echo $output->JSON(); echo $output->HAML(); echo $output->HTML(); echo $output->JADE();
Теперь вся логика по выводу информации пользователю представлена в классе SumCalculatorOutputter.
Принцип единственной обязанности используется в методологиях проектирования «от обязанности», таких как RDD и URDAD