Este Service Locator é um antipadrão?

Há um forte consenso na indústria de que o Service Locator é um antipadrão. Do wiki:





É importante notar que, em alguns casos, o localizador de serviço é na verdade um antipadrão.





Neste post, estou analisando um caso em que, na minha opinião, o Service Locator não é um antipadrão.





Aqui está o que eles escrevem na Internet sobre o Locator :





Alguns consideram o Service Locator um antipadrão. Ele viola o princípio de Inversão de Dependências do conjunto de princípios  SOLID . O Service Locator oculta as dependências de uma determinada classe em vez de compartilhá-las, como é o caso com o padrão Dependency Injection . Se essas dependências forem alteradas, corremos o risco de interromper a funcionalidade das classes que as utilizam, o que dificulta a manutenção do sistema.





O Service Locator anda de mãos dadas com o DI tão intimamente que alguns autores (Mark Seemann, Steven van Deursen) alertam especificamente :





O Service Locator é um padrão perigoso porque quase funciona. ... Há apenas uma área onde o Service Locator falha, e isso não deve ser considerado levianamente.





Ou seja, o Locator é muito bom e funciona quase como deveria, mas há uma coisa que estraga tudo. Aqui está:





O principal problema do  Service Locator é o impacto da capacidade de reutilização das classes que o consomem. Isso se manifesta de duas maneiras:









* A classe se arrasta pelo  Service Locator  como uma dependência redundante  .





* A classe torna não óbvio quais  são suas  dependências .





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





, :





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);
      
      



Nesta versão, o Service Locator torna-se um "padrão" sem qualquer "anti".








All Articles