Single Responsibility Principle — таким образом расшифровывается первая буква из аббревиатуры SOLID.
Как бы это банально не звучало, но в этом принципе, говориться только о том, чтобы ваш класс, отвечал только одной задаче, в этом классе, могут быть несколько методов, но служить они должны только для решения той задачи, которая возложена на данный класс.
Пример нарушения этого принципа.
Например мы парсим результаты ответа с социальной сети инстаграм, по определенному хештегу, у нас есть класс.
P.S.: приведен псевдокод, применять его в реальной жизни не стоит
Например наш класс имеет такой вид
<?php class ParseRequest { private $guzzle; public function __construct(Guzzle $guzzle) { $this->guzzle = $guzzle; } public function parse($url) { $data = $this->guzzle->get($url); return $this->getUsersLastPhotos($data); } public function getUsersLastPhotos($data) { // Собирает последние фото у пользователей инстаграма // из результата запроса } } ?>
Клиентский код
<?php $url = 'instagram.com/search?q=#какойтохештег'; $parse = new ParseRequest(new GuzzleHttp\Client()); $usersLastPhotos = $parse->parse($url); ?>
Грубый пример, но сразу видно что класс
отвечает за разбор запроса НО как именно будет разбираться этот запрос — гвоздями прибито в этом классе, что в принципе делает две задачи на один класс, это — КАК мы будем получать данные, и что мы будем с ними делать декомпозицию задачи и разбиение её на более конкретные части никто не отменял.
Попробуем разбить семантически, зоны ответственности в виде интерфейсов
interface IResource { public function getResource(); } interface IHandlerResource { public function handle(array $data=[]); }
Определим два интерфейса:
1. IResource — говорит нам, реализуй откуда ты возьмешь ресурс
2. IHandlerResource — говорит нам как и что ты будешь делать с этим ресурсом
Реализация первого интерфейса как базовый класс, который будет модифицироваться наследованием.
class InstagramResource implements IResource { protected $url; private $guzzle; protected $options; public function __construct(Guzzle $guzzle){ $this->guzzle = $guzzle; } public function getResource(){ return $this->guzzle->request($this->url, $this->options); } }
Пример модифицирования наследованием:
Здесь опишем пример того что будем получать ресурс из хештега, ну то есть через поиск
class ByHastagResource extends InstagramResource { protected $url = 'instagram.com/search?q=#somehastag'; public function __construct(Guzzle $guzzle){ parent::__construct($guzzle) } }
Реализация второго интерфейса, конкретный хендлер с методом который будет давать нам последние фото из каждого аккаунта, исходя из полученного массива данных
class InstagramLastPhotoHandler implements IHandlerResource { public function handle(array $data){ return $this->lastPhotos($data); } public function lastPhotos($data){ return // массив с последними фото пользователей } }
Класс агрегат, который будет собирать нашу общую задачу в одну, не имея конкретных реализаций, вся реализация осталась позади, реализация инкапсулирована и полиморфна, в отличии от первого примера.
class InstagramParser { private $resource; private $handler; public function __construct(IResource $resource, IHandlerResource $handler) { $this->resource = $resource; $this->handler = $handler; } public function parse() { return $this->handler ->handle($this->resource->getResource()); } }
Клиентский код
$instagramResource = new ByHastagResource(new Http\GuzzleClient()); $handler = new InstagramLastPhotoHandler(); $instagramParser = new InstagramParser($instagramResource, $handler); $lastPhotos = $instagramParser->parse(); var_dump($lastPhotos); // Результатом будет отсортированный массив данных с последними фотографиями пользователей исходной выборки
Декларируя интерфейсы, можно таким образом проектировать верхние уровни, но это не просто, точнее к этому нужно привыкнуть.
Итог:
Ответственности разделены на получение ресурса путем реализации интерфейса IResource. И то, что мы будем делать с этим ресурсом было описано интерфейсом IHandlerResource.
Придерживаясь принципа (Single Responsibility Principle) получаем конкретные реализации, а так же получаем гибкость в плане разной реализации и подхода для решения задачи
P.S.: Код местами утрирован и является показательным примером.