Приветствую вас в 6-ом эпизоде сериала “ООП здорового человека”. Здесь речь пойдет о 4-ем принципе SOLID – разделение интерфейсов. По истории этого принципа мне сказать нечего, потому перейдем к сути.
Теория
Принцип разделения интерфейса. Книга: Создавайте мелкозернистые интерфейсы, ориентированные на клиента – это дословный перевод; если же смысловой – будет звучать так: клиент не должен зависеть от методов, которые он не использует. Из принципа следует, что интерфейс это не принадлежность системы, а должен быть ассоциирован с клиентом и его потребностью.
Примеры
№1 Допустим мы в магазине выбираем товары; у них всех есть общие характеристики(цена, размеры, вес и т.д.);два товара – свитер(дополнительная х-ка материал) и машина(доп. мощность двигла). Принцип о том, что не нужно делать интерфейс со всеми свойствами(и существующими и нет в конкретном классе); нужно сделать 3 интерфейса: интерфейс продукта (с общими свойствами)и специфические к каждому отдельно.
№2 Это уже из моей “программистской” практики. Часть сайта представлял собой анкету, в которой, в зависимости от семейного положения клиента, открывались и закрывались различные блоки полей к заполнению. Было это сделано так: был один фасад(класс) со всеми полями; при выборе положения происходила проверка и по ее результатам некоторые поля в классе устанавливались в NULL. Каюсь, я этот момент не переделывал(времени не было + не мой фронт работ, я всего-лишь глянул что там). Если б я переделывал это в соответствии с ISP, было б где-то так: от фасада отпочковывается 1 интерфейс с общими для всех полями, и еще интерфейсы с индивидуальными полями для каждого состояния.
Практика
Раз уж я вспомнил о примере с работы(на деле это фриланс, без обязательств молчать), рассмотрю его в коде; иными словами – реализую это так, как я вижу(с применением ISP)
Для начала мы имеем общий класс, описывающий все свойства(это его примерный интерфейс)
<?php
interface PersonalDataInterface
{
public function setFamilyState($value);
public function setIndividualData($value);
public function setParentsData($value);
public function setFamilyData($value);
}
class PersonalData implements PersonalDataInterface
{
protected int $familyState;
protected array $individualData;
protected array $parentsData;
protected array $familyData;
public function setFamilyState($value)
{
$this->familyData = $value;
}
public function setIndividualData($value)
{
$this->individualData = $value;
}
public function setParentsData($value)
{
if ($this->familyState === 0) {
$this->parentsData = $value;
}
}
public function setFamilyData($value)
{
if ($this->familyState === 1) {
$this->familyData = $value;
}
}
}если очистить код от плевел – было так. После переписи получил это
<?php
interface IndividualDataInterface
{
public function setIndividualData($value);
}
interface ParentsDataInterface
{
public function setParentsData($value);
}
interface FamilyDataInterface
{
public function setFamilyData($value);
}
class MarriedPersonalData implements IndividualDataInterface, FamilyDataInterface
{
protected array $individualData;
protected array $familyData;
public function setIndividualData($value)
{
$this->individualData = $value;
}
public function setFamilyData($value)
{
$this->familyData = $value;
}
}
class TeenagerPersonalData implements IndividualDataInterface, ParentsDataInterface
{
protected array $individualData;
protected array $parentsData;
public function setIndividualData($value)
{
$this->individualData = $value;
}
public function setParentsData($value)
{
$this->parentsData = $value;
}
при этом поле familyState(из того как было) становится определителем используемого класса для построения объекта клиента.
На деле – примеров телега! Роли пользователей сайта, типы постов… В целом, это простой совет построения кода для обеспечения его гибкости(как и любой другой принцип). А еще этот принцип соблюдает SRP для интерфейсов.