Принцип розділення інтерфейсів (Interface Segregation Principle, «I» в SOLID): клієнти не повинні залежати від методів, якими вони не користуються. Краще кілька вузьких інтерфейсів, ніж один «товстий».
Порушення:
interface Storage
{
public function read(string $path): string;
public function write(string $path, string $contents): void;
public function delete(string $path): void;
public function temporaryUrl(string $path, DateTimeInterface $expires): string;
public function listContents(string $dir): array;
}
Клас, якому потрібно лише читати файли, залежить від усього інтерфейсу. Реалізація для сховища, де немає тимчасових посилань, змушена кидати NotSupportedException - а це вже порушення й принципу Лісков.
Відповідно до ISP:
interface ReadsFiles
{
public function read(string $path): string;
}
interface WritesFiles
{
public function write(string $path, string $contents): void;
public function delete(string $path): void;
}
interface GeneratesTemporaryUrls
{
public function temporaryUrl(string $path, DateTimeInterface $expires): string;
}
final class ReportGenerator
{
public function __construct(private ReadsFiles $files) {} // лише те, що потрібно
}
Один клас може реалізовувати кілька інтерфейсів, а кожен споживач залежить лише від потрібного.
Навіщо:
- простіші тести: фейк для
ReadsFiles- один метод, а не п'ять заглушок; - менше зв'язності: зміна методу запису не зачіпає класи, що лише читають;
- чесні реалізації: немає методів, що кидають «не підтримується»;
- зрозумілі залежності: з конструктора видно, що саме клас використовує.
Приклади в PHP і Laravel:
- PHP:
Countable,IteratorAggregate,ArrayAccess,JsonSerializable,Stringable- маленькі інтерфейси, кожен про одну можливість; - Laravel:
ShouldQueue,ShouldBroadcast,HasLocalePreference,Arrayable,Jsonable,Responsable- вузькі контракти, які клас реалізує за потреби.
Межа здорового глузду: інтерфейс з одним методом на кожен метод класу - теж крайність. Групувати варто за тим, як інтерфейс використовують клієнти: методи, які завжди потрібні разом, - в одному інтерфейсі.