2.4. Interface Segregation Principle - Принцип отделения интерфейса
Или много специализированных интерфейсов лучше, чем один универсальный. Другая формулировка принципа: клиенты не должны зависеть от методов, которые они не используют. Класс не должен зависеть от класса с большим количеством методов, из которых он использует только некоторые. Все эти формулировки выражают одну мысль: если мы определим большой универсальный интерфейс, тогда в наследниках возможно появление множества заглушек, а соответственно, много лишнего кода, который неудобно поддерживать.
Пример:
class ServiceAdapter
{
public function addUser(...) {...}
public function removeUser(...) {...}
public function getUsers(...) {...}
public function addList(...) {...}
public function removeList(...) {...}
public function getLists(...) {...}
public function addFoo(...) {...}
...
}
class UserController
{
public function __construct(ServiceAdapter $adapter)
{
// Even though we are only interested in getUser,
// code hinting gives us getUsers, getLists, getFoos...
//нам в этом классе нужен только пользователь, а здесь куча всего, что при каких //либо изменениях с большой вероятность придется править. И есть возможность некоректного использования методов.
$adapter->getUsers(…);
}
}
Более нормальным вариантом будет в таком случае следующий код:
interface ServiceUserAdapter
{
public function addUser(...);
public function removeUser(...);
public function getUsers(...);
}
...
class ServiceAdapter
implements ServiceUserAdapter, ServiceListAdapter, ...
{
public function addUser(...) {...}
public function removeUser(...) {...}
public function getUsers(...) {...}
public function addList(...) {...}
public function removeList(...) {...}
public function getLists(...) {...}
public function addFoo(...) {...}
...
}
class UserController
{
public function __construct(ServiceUserAdapter $adapter)
{
// Now code hinting only sees getUser(...)
$adapter->getUsers(…);
}
}
Здесь был выделен интерфейс ServiceUserAdapter и теперь при необходимости мы можем использовать только те методы, которые он объединяет. В данном случае класс UserController не знает о других методах ServiceAdapter и не сможет использовать их не по назначению.
Другими словами образный пример, если у нас есть класс МегаТрансформер, и он реализует интерфейс трансформера( трансформация в машину, трансформация в автобус и трансформация в самолет) и есть другой класс МиниТрансформер который так же реализует этот интерфейс, но может только например превратиться в машину, то для других методов придется делать заглушки, правильнее в таком случае, иметь 3 интерфейса, ТрансформерВМашину,ТрансформерВАвтобус и тд, то есть несколько маленьких, то есть мы избавляемся от лишнего кода.