ドメインモデルが明確に定義され、エンティティ、リポジトリ、サービスレイヤーを備えたMVCアプリケーションがあります。
コントローラー内でサービスクラスをインスタンス化する必要がないように、つまりコントローラーをそれらに適さないロジックで混乱させるために、一種のサービスロケーターとして機能するヘルパーを作成しましたが、少し読んだ後、多くの開発者が気づきました:
- http://blog.tfnico.com/2011/04/dreaded-service-locator-pattern.html
- http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx
- http://underground.infovark.com/2010/06/18/the-service-locator-pattern-is-the-new-global-variable/
- http://www.andyfrench.info/2011/05/service-locator-anti-pattern_17.html
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...
- 私の実装は正しいですか?
- それは本当にアンチパターンですか?
- 私が直面する可能性のある問題は何ですか?
- コードをリファクタリングしてこのアンチパターンを排除し、機能を継続するにはどうすればよいですか?