Ha, sungguh penyamaran dari Service Locator di bawah DI. Bahkan mungkin tampak seperti DI! :-)
Ini adalah komentar pertama untuk publikasi saya sebelumnya, Ketergantungan Injeksi, JavaScript, dan Modul ES6 . Terima kasih kolega symbix 'u untuk komentar ini, tk. dialah yang menjadi penyebab perendaman dalam seluk-beluk perbedaan antara satu dan yang lainnya. Di bawah potongan jawaban saya untuk pertanyaan dalam judul.

(KDPV tidak masuk akal dan dimaksudkan terutama untuk identifikasi visual publikasi ini, antara lain)
Untuk memulainya, kita akan berurusan dengan definisi ( beberapa contoh kode yang akan saya berikan di PHP, beberapa di JS, karena dua bahasa ini saat ini dalam bagasi aktif saya, dan beberapa di antaranya, karena saya mencuri contoh-contoh ini dari Internet ).
Ketergantungan injeksi
Singkatnya - alih-alih modul memerlukan / impor, Anda menyuntikkan dependensi melalui parameter konstruktor (atau properti setter). Artinya, di balik kata besar ini adalah sederhana "lulus kelas dependensi melalui parameter konstruktor".
Komentar kolega risedphantom ini dengan cukup akurat menyampaikan esensi dari fenomena tersebut. Untuk memfasilitasi pemahaman pengembang tentang kode, semua dependensi dijelaskan secara eksplisit - dalam bentuk parameter konstruktor (biasanya, tetapi tidak selalu):
class MainClass { public function __construct($dep1, $dep2, $dep3) {} }
Itu saja. DI - dia tentang itu. Ketergantungan yang kita butuhkan disediakan oleh seseorang di sana. Dan ke mana "seseorang di luar sana" membawa mereka - DI tidak peduli.
Saat menganalisis kode, penting untuk memahami apa sebenarnya โinternalโ untuk kode tersebut (dan apa yang dapat kita ubah dengan aman), dan apa yang datang / melampaui tanggung jawab kode ini. Inilah yang menggairahkan DI. Mengapa sebagian besar dependensi melewati konstruktor, dan bukan pada setter? Karena lebih nyaman bagi pengembang - ia segera melihat semua dependensi kode yang dianalisis di satu tempat. Kita terbiasa berpikir bahwa DI adalah sesuatu di tingkat kelas, tetapi parameter fungsi / metode juga DI:
function f(dep1, dep2, dep3) {}
Konstruktor hanyalah metode khusus di antara yang lainnya.
Pencari layanan
Service Locator adalah anti-pola yang terkenal. Apa yang dia lakukan Memberikan akses ke satu objek ke objek lain. Berikut adalah antarmuka khas untuk pelacak seperti itu:
interface ServiceLocator { public function addInstance(string $class, Service $service); public function addClass(string $class, array $params); public function has(string $interface): bool; public function get(string $class): Service; }
Locator adalah wadah tempat Anda dapat meletakkan objek yang sudah jadi (atau menetapkan aturan untuk pembuatannya) dan kemudian mengakses objek ini. Untuk locator, pada umumnya, tidak masalah bagaimana objek muncul di dalamnya - mereka secara eksplisit dibuat dari luar dan ditempatkan dalam wadah atau dibuat oleh wadah itu sendiri sesuai dengan aturan yang diberikan.
Pencari layanan bertanggung jawab untuk menyimpan objek dan menyediakan akses ke sana. Itu saja.
Ketergantungan Wadah Injeksi
Apa itu wadah DI? Menurut freeware menceritakan kembali isi " Prinsip, Praktek, dan Pola Injeksi Ketergantungan ": "perpustakaan perangkat lunak yang menyediakan fungsionalitas DI dan memungkinkan otomatisasi banyak tugas yang terlibat dalam Komposisi Objek, Intersepsi, dan Manajemen Seumur Hidup. Kontainer DI juga dikenal sebagai Inversi dari Control (IoC) Containers. (ยง3.2.2) "
Artinya, wadah DI terutama bertanggung jawab untuk membuat objek, tetapi hanya di kedua - untuk penyimpanan mereka. Wadah DI bahkan mungkin tidak menyimpan objek yang dibuat sama sekali, jika aplikasi itu sendiri tidak memerlukan objek yang umum untuk seluruh aplikasi (seperti konfigurasi atau logger).
Di sini, misalnya, adalah antarmuka wadah Symfony DI:
interface ContainerInterface extends PsrContainerInterface { public function set(string $id, ?object $service); public function get($id, int $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE); public function has($id); public function initialized(string $id); public function getParameter(string $name); public function hasParameter(string $name); public function setParameter(string $name, $value); }
Jika perlu, Anda dapat dengan mudah meyakinkan diri sendiri bahwa antarmuka wadah DI sangat mirip dengan antarmuka Layanan Locator - get
sama, get
dan set
/ add
.
Mengapa Lokasi Layanan buruk?
Tapi tidak ada apa-apa. Bukan template itu sendiri yang buruk, tetapi cara itu kadang-kadang digunakan. Secara khusus, ada pendapat bahwa " Layanan Locator melanggar enkapsulasi dalam bahasa yang diketik secara statis, karena pola ini tidak secara jelas mengekspresikan prasyarat ." Dan contoh pelanggaran:
public class OrderProcessor : IOrderProcessor { public void Process(Order order) { var validator = Locator.Resolve<IOrderValidator>(); if (validator.Validate(order)) { var shipper = Locator.Resolve<IOrderShipper>(); shipper.Ship(order); } } }
Seperti, itu sangat buruk, tapi bagus - seperti ini:
public class OrderProcessor : IOrderProcessor { public OrderProcessor(IOrderValidator validator, IOrderShipper shipper) public void Process(Order order) }
Hei, kami baru saja IOrderValidator
tanda kurung saat membuat objek sendiri dengan IOrderShipper
dan IOrderShipper
! Ada kemungkinan bahwa dalam aplikasi ini di tempat lain ada sesuatu seperti kode ini:
var validator = Locator.Resolve<IOrderValidator>(); var shipper = Locator.Resolve<IOrderShipper>(); var processor = new OrderProcessor(validator, shipper); processor.Process(order);
Akar komposisi
Berbicara tentang Injeksi Ketergantungan, kami tidak dapat membantu tetapi sampai pada konsep seperti Root Komposisi (selanjutnya saya akan menyebutnya "Titik Perakitan"). Ini adalah " seseorang " yang sama dengan siapa tanggung jawab untuk menciptakan dependensi dan implementasinya didelegasikan.
Di Assembly Point, semua dependensi didefinisikan secara eksplisit, objek yang sesuai dibuat dan diimplementasikan di mana mereka menunggu. Di sini perbedaan antara Layanan Locator dan wadah DI minimal. Baik itu dan yang lain memungkinkan untuk membuat objek baru, untuk menyimpan objek yang dibuat, untuk mengekstrak objek yang disimpan. Saya bahkan akan berusaha untuk menegaskan bahwa di tempat ini tidak ada perbedaan mendasar di antara mereka.
Perbedaan utama
Dan di mana perbedaan antara wadah DI dan wadah Layanan Locator yang paling jelas? Di tempat lain, dan terutama dengan akses statis ke wadah:
$obj = Container::getInstance()->get($objId);
Ini dia. Dalam bentuk ini, di mana saja (kecuali itu adalah Titik Perakitan, tetapi penggunaan akses statis sangat meragukan di sana), wadah apa pun menjadi pola anti yang disebut Pelokasi Layanan.
Seorang kolega VolCh menjawab dengan singkat dan ringkas pertanyaan saya:
Dan bagaimana menurut Anda DI yang benar berbeda dari Service Locator yang menyamar sebagai DI?
seperti ini:
Akses kontainer
Bahkan, seluruh publikasi ini hanyalah penyebaran yang lebih rinci dari jawabannya di sini.
Penggunaan wadah secara legal
Dengan demikian, apakah sebuah Kontainer adalah sebuah wadah DI atau sebuah wadah untuk Layanan Locator sangat bergantung pada di mana dan bagaimana kita menggunakannya. Seperti yang saya katakan di atas, di Assembly Point, perbedaan antara jenis wadah menghilang. Tetapi apa yang kita lewati jika wadah itu sendiri merupakan ketergantungan untuk kelas mana pun?
class Foo { public function __construct(Container $container){} }
Sekali lagi, itu semua tergantung pada bagaimana kita menggunakan wadah. Berikut adalah dua contoh, salah satunya persis cocok dengan wadah Layanan Locator dan merupakan anti-pola, sementara yang lain memiliki hak untuk hidup dalam kondisi tertentu.
class Foo { private $dep; public function __construct(Container $container) { $this->dep = $container->get('depId'); } }
class Foo { private $container; public function __construct(Container $container) { $this->container = $container; } public function initModules($modules) { foreach ($modules as $initClassId) { $init= $this->container->get($initClassId); $init->exec(); } } }
Ringkasan
Faktanya, semuanya agak lebih rumit, wadah DI harus memiliki lebih banyak fungsi daripada Pencari Lokasi Layanan, tetapi inti dari publikasi ini adalah bahwa wadah DI yang paling canggih pun dapat dengan mudah digunakan sebagai Pencari Layanan, tetapi untuk menggunakan Pencari Layanan sebagai wadah DI - Anda harus mencoba.
PS
Saya tidak bisa membantu tetapi memberikan tautan ke blog Pemrograman barang milik Sergei Teplyakov - masalah ini dibahas dengan sangat baik di sana.