PHP设计模式-服务定位模式 ServiceLocator

在PHP服务定位设计模式(Service Locator)中,抽象层对涉及尝试获取一个服务的过程进行封装。该模式使用一个称为”Service Locator”的中心注册表来处理请求并返回处理特定服务。服务定位器知道如何控制应用程序需要的所有服务。

服务定位模式PHP如何设计:使用ServiceLocator为指定接口注册服务。通过使用接口不用知道它的实现就可以获取服务并在应用的类中使用该服务。而在启动的时候我们就可以注入Service Locator对象。

Service Locator模式和依赖注入模式(DI)都是IoC原则的一种实现,据说Java中Spring框架完美实现了IoC容器。但DI的依赖接口完全由IoC容器装配提供,而服务定位模式需要由对象内部代码显式调用,即由对象主动去获取自己所依赖的接口。

Zend Framework 2 使用 Service Locator 创建框架中共享的服务(如 EventManager, ModuleManager, 由 modules 提供的所有用户自定义服务等…)。下面是PHP示例代码:

interface DatabaseServiceInterface
{
}

class DatabaseService implements DatabaseServiceInterface
{
}

interface LogServiceInterface
{
}

class LogService implements LogServiceInterface
{
}
interface ServiceLocatorInterface
{
    // 检查服务是否注册
    public function has($interface);

    // 获取接口的已注册服务
    public function get($interface);
}
class ServiceLocator implements ServiceLocatorInterface
{
    // 包含所有服务名称的容器
    private $services;

    // 含有实例的服务容器
    private $instantiated;

    // 服务是否可共享
    private $shared;

    public function __construct()
    {
        $this->services     = array();
        $this->instantiated = array();
        $this->shared       = array();
    }

    // 注册特定接口的服务
    // 添加服务时,即使可能会修改服务的实现,也要带上接口或一个字符串
    public function add($interface, $service, $share = true)
    {
        if (is_object($service) && $share) {
            $this->instantiated[$interface] = $service;
        }
        $this->services[$interface] = (is_object($service) ? get_class($service) : $service);
        $this->shared[$interface]   = $share;
    }

    // 检查服务是否注册
    public function has($interface)
    {
        return (isset($this->services[$interface]) || isset($this->instantiated[$interface]));
    }

    // 获取接口的已注册服务
    public function get($interface)
    {
        // 获取存在且共享的服务
        if (isset($this->instantiated[$interface]) && $this->shared[$interface]) {
            return $this->instantiated[$interface];
        }

        // 否则获取服务类
        $service = $this->services[$interface];

        // 检查$servic服务类是否存在,是否允许实例化
        // 可以看 $service 是一个工厂还是类
        // 如果注册的$service是工厂那就可以用DependencyInjection 模式
        // ...

        $object = new $service();

        // 如果服务必须共享的话,进行实例化注册对象到容器中
        if ($this->shared[$interface]) {
            $this->instantiated[$interface] = $object;
        }
        return $object;
    }
}
// 客户端调用
$serviceLocator  = new ServiceLocator();
$logService      = new LogService();
$serviceLocator->add('LogServiceInterface', $logService, false);
$serviceLocator->get('LogServiceInterface'));

Leave a Reply

Your email address will not be published. Required fields are marked *