11

私がサービスを持っているとしましょう:

namespace Helloworld\Service;

class GreetingService
{
    public function getGreeting()
    {
        if(date("H") <= 11)
            return "Good morning, world!";
        else if (date("H") > 11 && date("H") < 17)
            return "Hello, world!";
        else
            return "Good evening, world!";
    }
}

そして私はそれのために呼び出し可能なものを作成します

public function getServiceConfig()
{
    return array(
        'invokables' => array(
            'greetingService'
                => 'Helloworld\Service\GreetingService'
        )
    );
}

それから私のコントローラーで私はすることができました:

public function indexAction()
{
    $greetingSrv = $this->getServiceLocator()
        ->get('greetingService');

    return new ViewModel(
        array('greeting' => $greetingSrv->getGreeting())
    );
}

おそらくこれにより、コントローラーがサービス(およびServiceManager)に依存するようになります

より良い解決策は、そのサービスのファクトリを作成するか、ServiceManagerでクロージャを返し、コントローラでセッターを作成することです。

class IndexController extends AbstractActionController
{
    private $greetingService;

    public function indexAction()
    {

        return new ViewModel(
            array(
                'greeting' => $this->greetingService->getGreeting()
            )
        );
    }

    public function setGreetingService($service)
    {
        $this->greetingService = $service;
    }
}

'controllers' => array(
    'factories' => array(
        'Helloworld\Controller\Index' => function($serviceLocator) {
            $ctr = new Helloworld\Controller\IndexController();

            $ctr->setGreetingService(
                $serviceLocator->getServiceLocator()
                    ->get('greetingService')
            );

            return $ctr;
        }
    )
)

私の質問はなぜですか?2番目のアプローチが最初のアプローチよりも優れているのはなぜですか?そしてそれはどういう意味controller is dependent of the serviceですか?

ありがとう

4

4 に答える 4

13

これは、インターフェイスの実装ServiceManagerを拡張するため、デフォルトで任意のZF2コントローラー内に挿入されます。AbstractControllerServiceLocatorAwareInterface

2番目のアプローチには、「冗長性」の形式があります。これは、インスタンスに既にアクセスできることに加えてServiceManager、コントローラー間でサービスを共有する必要がある場合は常に、コントローラーごとにインジェクションメカニズムを構成する必要があるためです。コントローラにはすでにServiceManagerに対する依存関係があるため、最初のアプローチを使用してドメイン関連サービスをに登録ServiceManagerし、サービス層へのアクセスを一元化する方が理にかなっています。

注:回答の次の部分は質問の範囲を超える可能性がありますが、元の質問の「隠された」背景を提供することを目的としています。

複雑なシステムを構築していると仮定しましょう。その中で、低結合、再利用性、およびテスト性が促進されます。私たちのシステムは多層化されており、サービス層まですべてを構築しました。これまで、「MVC」Webレイヤーを検討したり、特定のフレームワークを選択したりすることはまだありませんでした。

サービスレイヤー(質問で言及されているレイヤーであるため、このレイヤーを検討します)内では、ビジネスロジックとオブジェクトグラフの構築(または依存関係の解決)を分離する原則を採用したと想定しています。したがって、おそらく、工場を通じて構築される複雑なサービスがいくつかあります。

サービスレイヤーが構築されたので、ZF2の上に「プラグイン」することにしました。当然のことながら、私たちのサービスはコントローラーからアクセスできる必要があります。あなたの質問がそれを示しているように、私たちはそれを行う方法以上のものを持っています。ただし、冗長性を避け、すでに構築したものを活用したいと考えています。次の工場を想定しましょう:

//The following class is a part of our Service layer
public class ComplexServiceFactory{

    private dependencyA;
    private dependencyB;

    public function buildComplexService()
    {
        $service = new ComplexService();
        $service->setDependencyA($this->dependecyA);
        $service->setDependencyB($this->dependecyB);
        return $service;
    }

}

ServiceManagerここで行うことは、ロジックで使用できるようにファクトリを調整(実際には拡張)することです。このクラスは、システムをZF2に「プラグイン」するために使用されるメカニズムの一部と見なすことができます(実際にはアダプターです) 。

public class SMComplexServiceFactory extends ComplexServiceFactory implements
    Zend\ServiceManager\FactoryInterface
{

    public function createService(ServiceLocatorInterface $sm)
    {
        $this->setDependencyA($sm->get('dependecyA'));
        $this->setDependencyB($sm->get('dependecyB'));
        return parent::buildComplexService;
    }

}

そうすることで、オブジェクトグラフの構築をMVCレイヤーに持ち込むことはありません(そうしないと、関心の分離違反と不要なクロスレイヤーカップリングになります)。Service Manager +「Adapted」ファクトリクラスは、ある意味で依存関係解決メカニズムです。実際のところ、私たちのシステムはまだ移植可能です。たとえば、別のシステム(別のフレームワーク)を選択して、MVCプラットフォームに対する依存度を低くすることができます。

于 2013-01-27T19:26:02.877 に答える
4

非常に役立つ質問です。彼は繰り返し育てられてきました。ここで正確な答えを得ることができると思います

于 2013-09-26T16:24:49.613 に答える
3

@yechabbisの回答に何かを追加するには:

のファクトリパターンは、ServiceConfiguration実際には複雑なインフラストラクチャ用であるか、または単に構成内でclosures/を使用しないためのものです。callable functionsこれには2つの理由があります。

  • 読みやすさ/クリーナーコード
  • パフォーマンス

内部にファクトリパターンを設定することgetServiceConfigは、素晴らしく、クリーンで、高速です。クラスはインスタンス化されませんが、サービスキーの呼び出し時にインスタンス化されます。ただし、クロージャパターンまたは呼び出し可能関数を使用してサービスを設定した場合、これらのクラスは、リクエストごとに常にインスタンス化されます。

これはおそらく単なる例ですが、あなたが示したコードは、ViewHelper

于 2013-01-28T06:29:43.937 に答える
0

コントローラクラスをGreetingServiceから独立させるという2番目のアプローチの方が優れていると思います。このアプローチは、別のグリーティングサービスを使用してコントローラが使用する場合に役立ちます。コントローラクラスのコードを変更する必要はまったくありません。代わりに、ファクトリクロージャでサービスマネージャを変更することで変更します。

これが制御の反転または依存性注入の主なアイデアであると私は信じています。すべての配線と構成はクラス(この場合はコントローラークラス)の外部で行われます。

だから、私の意見では、それが2番目のアプローチがより良いものである理由です。

于 2013-07-14T15:45:33.177 に答える