Ответ
Паттерн Service Locator, при котором класс явно запрашивает зависимости из глобального реестра, нарушает два ключевых принципа SOLID:
1. Принцип инверсии зависимостей (D — Dependency Inversion Principle): Это главное нарушение. Вместо того чтобы зависимости предоставлялись классу извне (через конструктор или сеттер), класс сам знает о конкретном механизме их получения (сервис-локаторе). Это создаёт скрытую зависимость от глобального состояния.
2. Принцип единственной ответственности (S — Single Responsibility Principle): Класс начинает нести дополнительную ответственность — знание о том, как и где найти свои зависимости, что усложняет его логику.
Сравнение на примере:
// Нарушение DIP и SRP с Service Locator
class OrderProcessor {
private $mailer;
private $logger;
public function __construct() {
// Класс знает о конкретной реализации локатора
$this->mailer = ServiceLocator::get(MailService::class);
$this->logger = ServiceLocator::get(LoggerInterface::class);
}
public function process(Order $order) {
// ... логика
$this->mailer->sendReceipt($order);
}
}
// Тестирование сложно — нужно настроить глобальный ServiceLocator.
// Соблюдение SOLID с внедрением зависимостей (Dependency Injection)
class OrderProcessor {
public function __construct(
private MailServiceInterface $mailer,
private LoggerInterface $logger
) {}
public function process(Order $order) {
// ... логика
$this->mailer->sendReceipt($order);
}
}
// Зависимости явны. Тестирование простое — можно передать моки.
$processor = new OrderProcessor(new MockMailer(), new NullLogger());
Service Locator создаёт неявные связи, затрудняет понимание зависимостей класса и его модульное тестирование, поэтому в современной разработке предпочтение отдаётся явному внедрению зависимостей (Dependency Injection).