DIとDIコンテナとサービスロケータ その3
DI PHP 設計
Published: 2018-02-22

本記事の範囲

本記事では、サービスロケータ を記事の範囲とします。 DI 、DI コンテナについては別記事で書いています。

サービスロケータとは

「サービスロケータ」とは、サービス(オブジェクト)の取得を抽象化するデザインパターンです。

サービスロケータの例

<?php

require_once './vendor/autoload.php';

use Pimple\Container;

class Client
{
    private $container;

    public function __construct(Container $container)
    {
        $this->container = $container;
    }

    public function log($messgae)
    {
        $this->container['service_interface']->log();
    }
}

interface ServiceInterface
{
    public function log();
}

class Service implements ServiceInterface
{
    public function log($message)
    {
		echo $message . "\n";
    }
}

// Client呼び出し

$container = new Container();

$container['service_interface'] = function ($container) {
    $service = new Service();
    return $service;
};

$container['client'] = function ($container) {
    $client = new Client($container);
    return $client;
};

$client = $container['client'];
$client->log('ssssss');

ここでは、$container がサービスロケータとなります。

依存するものが DIとサービスロケータで異なります。

DIの場合

  • ServiceInterface を実装しているオブジェクト

サービスロケータの場合

  • DIコンテナ (Pimple)
  • $this->container['service_interface']

これによって、Client クラスが DIコンテナ (Pimple)の依存が強くなり、Client を利用するときは DIコンテナも必要とされるようになってしまいました。

DIコンテナについてまず知っておくべきなのは、DIコンテナを使ってさえいれば「依存性の注入」ができるわけではないってことだ。 DIコンテナは、依存性の注入を実現するための便利な道具として使える。 でも、使い方をミスって、サービスロケーションというアンチパターンを作ってしまっていることも多い。 DIコンテナをサービスロケーターとしてクラスに組み込んでしまうと、 依存関係を別の場所に移そうとしていたはずなのに、よりきつい依存関係を作り込むことになる。 おまけにそのコードはわかりにくくなってしまうし、テストもしづらくなる。

結局のところ、サービスロケータはアンチパターンのようです。

参考