Apakah Service Locator ini anti-pola?

Ada konsensus yang kuat di industri bahwa Pencari Lokasi Layanan adalah anti-pola. Dari wiki:





Perlu dicatat bahwa dalam beberapa kasus, pencari lokasi sebenarnya adalah anti-pola.





Dalam posting ini, saya melihat kasus di mana, menurut saya, Pencari Layanan bukanlah anti-pola.





Inilah yang mereka tulis di Internet tentang Locator :





Beberapa orang menganggap Service Locator sebagai anti-pola. Ini melanggar prinsip Dependency Inversion dari sekumpulan prinsip  SOLID . Service Locator menyembunyikan dependensi dari kelas tertentu alih-alih membagikannya, seperti halnya dengan pola Injeksi Ketergantungan . Jika dependensi ini berubah, kami berisiko merusak fungsionalitas kelas yang menggunakannya, yang menyulitkan pemeliharaan sistem.





Service Locator berjalan seiring dengan DI sehingga beberapa penulis (Mark Seemann, Steven van Deursen) secara khusus memperingatkan :





Service Locator adalah pola yang berbahaya karena hampir berhasil. ... Hanya ada satu area di mana Service Locator gagal, dan itu tidak boleh dianggap enteng.





Artinya, Locator sangat bagus dan berfungsi hampir sebagaimana mestinya, tetapi ada satu hal yang merusak segalanya. Ini dia:





Masalah utama dengan  Service Locator adalah dampak usabilitas kelas yang memakannya. Ini memanifestasikan dirinya dalam dua cara:









* Kelas menyeret  Service Locator  sebagai Dependensi yang berlebihan  .





* Kelas membuatnya tidak jelas apa  Dependensinya  .





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





, :





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



Dalam versi ini, Service Locator menjadi sangat "pola" tanpa "anti".








All Articles