このサービスロケーターはそのようなアンチパターンですか?

業界では、ServiceLocatorがアンチパターンであるという強いコンセンサスがあります。ウィキから:





場合によっては、サービスロケーターが実際にはアンチパターンであることに注意してください。





この投稿では、私の意見では、ServiceLocatorがアンチパターンではない場合を検討しています。





これが彼らがロケーターについてインターネット上で書いていることです:





ServiceLocatorをアンチパターンと見なす人もいます。これは、SOLIDの一連の原則 依存性逆転の原則に違反しています。Service Locatorは、依存性注入パターンの場合のように、特定のクラスの依存関係を共有するのではなく非表示にしますこれらの依存関係が変更されると、それらを使用するクラスの機能が損なわれるリスクがあり、システムの保守が困難になります。





Service LocatorはDIと密接に関連しているため、一部の作成者(Mark Seemann、Steven van Deursen)は特に警告しています。





Service Locatorはほとんど機能するため、危険なパターンです。... Service Locatorが不足している領域は1つだけなので、軽視すべきではありません。





つまり、ロケーターは非常に優れており、ほぼ正常に機能しますが、すべてを台無しにすることが1つあります。ここにあります:





Service Locatorの主な問題 は、それを消費するクラスの再利用性の影響です。これは2つの方法で現れます:









*クラスは 、冗長な依存関係としてサービスロケーターに沿ってドラッグ します 





*クラスは、その依存関係 が何であるかを非自明にし ます。





.., : -, - , -, , .





, :





public function __construct(IDep1 $dep1, IDep2 $dep2, IDep3 $dep3)
{
    $this->dep1 = $dep1;
    $this->dep2 = $dep2;
    $this->dep3 = $dep3;
}
      
      



- :





public function __construct(ILocator $locator)
{
    $this->locator = $locator;
    $this->dep1 = $locator->get(IDep1::class);
    $this->dep2 = $locator->get(IDep2::class);
    $this->dep3 = $locator->get(IDep3::class);
}
      
      



() (, ):





Property Injection should only be used when the class you’re developing has a good Local Default, and you still want to enable callers to provide different implementations of the class’s Dependency. It’s important to note that Property Injection is best used when the Dependency is optional. If the Dependency is required, Constructor Injection is always a better pick.





:





public function __construct(ILocator $locator = null)
{
    if ($locator) {
        $this->dep1 = $locator->get(IDep1::class);
    }
}

public function setDep1(IDep1 $dep1)
{
    $this->dep1 = $dep1;
}
      
      



, ) (, ), ) setter' ( , , "" , Ctrl+F "$locator->get" ).





, , , . " Dependency Injection Service Locator?" @symbix :





SL pull: "" .





DI push: .





.., , DI- Service Locator:





// push deps into constructor
public function __construct(IDep1 $dep1, IDep2 $dep2, IDep3 $dep3) {}

// pull deps from constructor
public function __construct(IContainer $container) {
    if ($container) {
        $this->dep1 = $container->get(IDep1::class);
        $this->dep2 = $container->get(IDep2::class);
        $this->dep3 = $container->get(IDep3::class);
    }
}
      
      



, , - -. ? , , , , - .. . .., , , , .





"-" Service Locator "" :





class App {
    /** @var \IContainer */
    private $container;
    /** @var \IDep1 */
    private $dep1;

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

    private function initDep1() {
        if (!$this->dep1) {
            $this->dep1 = $this->container->get(IDep1::class);
        }
        return $this->dep1;
    }

    public function run() {
        $dep1 = $this->initDep1();
    }

    public function setDep1(IDep1 $dep1) {
        $this->dep1 = $dep1;
    }

}
      
      



, :





  • setter (, );





  • private- init



    ;





  • , .





Service Locator . - ( "push") DI- , . "pull" , :





$this->dep1 = $this->container->get(IDep1::class, self::class);
      
      



このバージョンでは、ServiceLocatorは「アンチ」のない非常に「パターン」になります。








All Articles