這被認為是一種反模式!
對于某些人來說,服務定位器被認為是一種反模式。它違反了依賴倒置原則。服務定位器隱藏類的依賴關系,而不是像使用依賴注入那樣暴露它們。如果這些依賴項發(fā)生變化,您可能會破壞使用它們的類的功能,從而使您的系統(tǒng)難以維護。
實現(xiàn)松散耦合的架構以獲得更好的可測試、可維護和可擴展的代碼。DI 模式和服務定位器模式是逆控制模式的一種實現(xiàn)。
使用ServiceLocator您可以為給定接口注冊服務。通過使用該接口,您可以檢索服務并在應用程序的類中使用它,而無需知道它的實現(xiàn)。您可以在引導程序上配置和注入服務定位器對象。
Service.php
<?php namespace DesignPatterns\More\ServiceLocator; interface Service { }
ServiceLocator.php
<?php declare(strict_types=1); namespace DesignPatterns\More\ServiceLocator; use OutOfRangeException; use InvalidArgumentException; class ServiceLocator { /** * @var string[][] */ private array $services = []; /** * @var Service[] */ private array $instantiated = []; public function addInstance(string $class, Service $service) { $this->instantiated[$class] = $service; } public function addClass(string $class, array $params) { $this->services[$class] = $params; } public function has(string $interface): bool { return isset($this->services[$interface]) || isset($this->instantiated[$interface]); } public function get(string $class): Service { if (isset($this->instantiated[$class])) { return $this->instantiated[$class]; } $args = $this->services[$class]; switch (count($args)) { case 0: $object = new $class(); break; case 1: $object = new $class($args[0]); break; case 2: $object = new $class($args[0], $args[1]); break; case 3: $object = new $class($args[0], $args[1], $args[2]); break; default: throw new OutOfRangeException('Too many arguments given'); } if (!$object instanceof Service) { throw new InvalidArgumentException('Could not register service: is no instance of Service'); } $this->instantiated[$class] = $object; return $object; } }
LogService.php
<?php declare(strict_types=1); namespace DesignPatterns\More\ServiceLocator; class LogService implements Service { }
Tests/ServiceLocatorTest.php
<?php declare(strict_types=1); namespace DesignPatterns\More\ServiceLocator\Tests; use DesignPatterns\More\ServiceLocator\LogService; use DesignPatterns\More\ServiceLocator\ServiceLocator; use PHPUnit\Framework\TestCase; class ServiceLocatorTest extends TestCase { private ServiceLocator $serviceLocator; public function setUp(): void { $this->serviceLocator = new ServiceLocator(); } public function testHasServices() { $this->serviceLocator->addInstance(LogService::class, new LogService()); $this->assertTrue($this->serviceLocator->has(LogService::class)); $this->assertFalse($this->serviceLocator->has(self::class)); } public function testGetWillInstantiateLogServiceIfNoInstanceHasBeenCreatedYet() { $this->serviceLocator->addClass(LogService::class, []); $logger = $this->serviceLocator->get(LogService::class); $this->assertInstanceOf(LogService::class, $logger); } }
更多建議: