4

ドメインモデルが明確に定義され、エンティティ、リポジトリ、サービスレイヤーを備えたMVCアプリケーションがあります。

コントローラー内でサービスクラスをインスタンス化する必要がないように、つまりコントローラーをそれらに適さないロジックで混乱させるために、一種のサービスロケーターとして機能するヘルパーを作成しましたが、少し読んだ後、多くの開発者が気づきました:

ServiceLocatorは実際にはアンチパターンであると言います。しかし、私の実装はアンチパターンではないと思います。

彼らがServiceLocatorをアンチパターンと見なす理由は、依存関係を非表示にするためですが、必要な唯一の依存関係(Entity Managerであり、この依存関係はServiceインターフェイスのシグネチャにあるため変更されない可能性があります)を挿入しますサービスクラスによって、サービスロケーターをインスタンス化するときに。

これが私のコードです:

<?php

namespace App\Controller\Action\Helper;
use Zend_Controller_Action_Helper_Abstract as Helper,
    Doctrine\ORM\EntityManager;

/**
 * Service Locator Helper
 * @author JCM
 */
class Service extends Helper {

    /**
     * The actual EntityManager
     * @var \Doctrine\ORM\EntityManager
     */
    private $entityManager;

    /**
     * Services Namespace
     * @var string
     */
    private $ns;

    /**
     * @param EntityManager $entityManager
     * @param string $ns The namespace where to find the services
     */
    public function __construct( EntityManager $entityManager, $ns )
    {
        $this->entityManager = $entityManager;
        $this->ns = $ns;
    }

    /**
     * @param string $serviceName
     * @param array $options
     * @param string $ns
     */
    public function direct( $serviceName, array $options = array(), $ns = null )
    {
        $ns = ( (!$ns) ? $this->ns : $ns ) . '\\';
        $class = $ns . $serviceName;

        return new $class( $this->entityManager, $options );
    }

    /**
     * @param EntityManager $entityManager
     */
    public function setEntityManager( EntityManager $entityManager )
    {
        $this->entityManager = $entityManager;
    }

    /**
     * @return \Doctrine\ORM\EntityManager
     */
    public function getEntityManager()
    {
        return $this->entityManager;
    }

    /**
     * @param string $name
     */
    public function __get( $name )
    {
        return $this->direct( $name );
    }
}

アクションヘルパーをフロントコントローラーに登録する:

//inside some method in the bootstrap
HelperBroker::addHelper( new App\Controller\Action\Helper\Service( $entityManager, '\App\Domain\Service' ) );

そして、コントローラーでこのヘルパーをどのように使用するか:

//Some Controller
$myService = $this->_helper->service( 'MyService' ); //returns an instance of the class App\Domain\Service\MyService
$result = $myService->doSomethingWithSomeData( $this->getRequest()->getPost() );
//etc...
  • 私の実装は正しいですか?
  • それは本当にアンチパターンですか?
  • 私が直面する可能性のある問題は何ですか?
  • コードをリファクタリングしてこのアンチパターンを排除し、機能を継続するにはどうすればよいですか?
4

1 に答える 1

4

あなたが構築したものがサービスロケーターパターンを実装しているとは思いません。もしそうなら、どこかにグローバルな「レジストリ」があるでしょう。

私が見ているのは基本的にApp\Controller\Action\Helper\Service、ctorを介して注入される依存関係を持つファクトリクラス()です。したがって、クラスは依存関係がどこから来たのかを知らず、依存関係を作成する責任もありません(これは良いことです!)。

私が間違っている場合は私を訂正してください。:)

ところで:それは、依存性注入コンテナを渡してはいけない理由でもあります。それはサービスロケーターに変わります。

于 2012-01-25T23:36:27.887 に答える