Modul peringkat tinggi tidak boleh bergantung pada modul peringkat rendah. Kedua-duanya harus bergantung pada abstraksi.
Abstraksi tidak harus bergantung pada butiran, butiran harus bergantung pada abstraksi.
Mari kita fahami modul peringkat tinggi dan modul peringkat rendah melalui contoh:
Dalam aplikasi e-dagang seperti Flipkart pada tahap tinggi, ia boleh dikategorikan sebagai ProductCatalog, PaymentProcessor dan CustomerProfile (ini adalah beberapa fungsi perniagaan utama)
Fungsi perniagaan ini saling bergantung pada modul lain yang ditunjukkan dalam imej di atas.
Nota: modul di atas lebih dekat dengan fungsi perniagaan yang dipanggil Modul tahap tinggi.
Modul di bahagian bawah adalah hampir dengan butiran pelaksanaan yang dipanggil modul tahap Low.
Modul peringkat rendah ialah SQLProductRepository, GooglePayService, WireTransfer, EmailSender dan VoiceDialer.
Jika kita menganggap CustomerProfile (modul Tahap Tinggi) dan modul Komunikasi sahaja, Komunikasi ialah modul peringkat Rendah tetapi jika kita menganggap Komunikasi, EmailSender dan VoiceDialer sahaja, Komunikasi menjadi modul Tahap Tinggi, dan EmailSender dan VoiceDialer adalah Modul Aras Rendah.
Maksudnya di sini konsep modul peringkat Tinggi dan Rendah bukanlah mutlak tetapi relatif.
Menurut imej di atas ProductCatalog bergantung pada SQLProductRepository iaitu modul peringkat tinggi bergantung pada modul peringkat rendah, tetapi ini secara langsung bercanggah dengan takrifan pertama DIP.
Mari ambil ProductCatalog → perhubungan SQLProductRepository dan menganalisisnya dengan lebih lanjut.
import java.util.List; /* * High-Level module */ public class ProductCatalog { public void listAllProducts(){ SQLProductRepository sqlProductRepository = new SQLProductRepository(); List<String> allProductsNames = sqlProductRepository.getAllProductNames(); //Display all products names } }
/* * Low-level module */ import java.util.Arrays; import java.util.List; public class SQLProductRepository { public List<String> getAllProductNames(){ return Arrays.asList("soap","toothpaste"); } }
Oleh kerana ProductCatalog bergantung secara langsung pada SQLProductRepository, ini jelas merupakan pelanggaran definisi DIP 1 (mengikut takrifan kedua-dua modul peringkat Tinggi dan Rendah harus bergantung pada abstraksi)
Mari kita betulkan ini seperti definisi 1:
membuat antara muka ProductRepository
import java.util.List; public interface ProductRepository { public List<String> getAllProductNames(); }
Melaksanakan antara muka ini dalam SQLProductRepository
/* * Low-level module */ import java.util.Arrays; import java.util.List; public class SQLProductRepository implements ProductRepository{ @Override public List<String> getAllProductNames(){ return Arrays.asList("soap","toothpaste"); } }
Akhir sekali untuk modul peringkat Tinggi ProductCatalog kami tidak boleh terus instantiate SQLProductRepository di dalamnya. Kami akan menggunakan kelas ProductFactory untuk perkara yang sama
public class ProductFactory { public static ProductRepository create(){ return new SQLProductRepository(); } }
Kami akan menggunakan ProductFactory untuk membuat instantiate SQLProductRepository
/* * High-Level module */ import java.util.List; public class ProductCatalog { public void listAllProducts(){ ProductRepository productRepository = ProductFactory.create(); List<String> allProductsNames = productRepository.getAllProductNames(); //Display all products names } }
Perhatikan objek rujukan kami ialah ProductRepository Jadi, kami tidak mempunyai gandingan yang ketat dengan SQLProductRepository
Selepas pengubahsuaian, kebergantungan baharu akan kelihatan seperti ini
Perubahan di atas adalah seperti definisi DIP 1.
Perubahan kod di atas juga mengikut takrifan ke-2 DIP juga iaitu Abstraksi tidak boleh bergantung pada butiran, butiran harus bergantung pada abstraksi.
Seperti yang dapat kita lihat dalam imej di atas SQLProductRepository bergantung pada ProductRepository bukan sebaliknya. Inilah sebab mengapa prinsip ini dipanggil Prinsip Inversi Ketergantungan
Even though they are related, they are not the same and can not be used interchangeably
Memahami Suntikan Ketergantungan:
Dalam ProductCatalog kami menggunakan kaedah Factory ProductFactory.create() untuk mendapatkan contoh objek SQLProductRepository.
Walaupun ia mewakilkan proses penciptaan instance kepada kelas kilang ProductFactory, proses pemula masih dengan kelas ProductCatalog.
Sebaik-baiknya, kami tidak mahu kelas ProductCatelog bimbang tentang cara dan bila untuk mencetuskan instantiasi.
Bagaimana jika kami menyediakan kelas ProductRepository instan kepada ProductCatalog walaupun tanpa ia bertanya?
Jadi, kelas Utama ECommerceMainApplication menggunakan kaedah kilang ProductFactory.create() untuk mencipta contoh ProductRepository dan tika ini diluluskan sebagai hujah dalam pembina kelas ProductRepositroy.
public class ECommerceMainApplication { public static void main(String agrs[]) { ProductRepository productRepository = ProductFactory.create(); ProductCatalog productCatalog = new ProductCatalog(productRepository); productCatalog.listAllProducts(); } }
Selepas mengemas kini kelas ProductCatalog dengan sewajarnya
import java.util.List; public class ProductCatalog { private ProductRepository productRepository; public ProductCatalog(ProductRepository productRepository) { this.productRepository = productRepository; } public void listAllProducts(){ List<String> allProductsNames = productRepository.getAllProductNames(); //Display all products names allProductsNames.forEach(product-> System.out.println(product)); } }
Kini ProductCatalog bebas untuk menggunakan objek SQLProductRepository pada bila-bila masa dan di mana sahaja ia mahu. Ia tidak lagi bimbang untuk mencipta objek SQLProductRepository sendiri.
Dalam erti kata lain kami menyuntik kebergantungan ke dalam ProductCatalog dan bukannya ProductCatalog yang membimbangkan tentang mewujudkan kebergantungan.
Inilah konsep suntikan kebergantungan
Walaupun ia bukan sebahagian daripada DIP(Prinsip Penyongsangan Kebergantungan), ia berkait rapat
Mari kita fahami ini dengan kod yang sama di atas
Kelas ProductCatalog mempunyai pembina yang mengambil objek ProductRepository.
Kelas yang memanggil ProductCatalog akan menyediakan atau menyuntik objek ProductRepository dalam kes ini ia adalah ECommerceMainApplication.
Ambil perhatian, walaupun suntikan berlaku di luar kelas ProductCatalog, suntikan masih berlaku semasa aliran utama program. iaitu suntikan sedang berlaku dalam utas utama pelaksanaan program.
Bagaimana jika kita mahu semua suntikan berlaku dalam benang yang berasingan atau konteks yang berasingan sama sekali Supaya aliran kawalan utama diasingkan sepenuhnya daripada suntikan?
Ini boleh dicapai menggunakan rangka kerja seperti Spring(di Jawa).
Spring akan menjalankan konteksnya sendiri berbeza daripada aliran utama program
Spring akan menguruskan menyuntik kebergantungan yang diperlukan kelas. Jadi, jika anda ingin membuat instantiate objek kelas, bukannya melakukannya sendiri secara langsung dalam kod, anda meminta Spring memberikan objek kelas itu kepada anda.
Rangka kerja Spring melihat semua kebergantungan yang diperlukan untuk instantiasi objek, kemudian meneruskan dan menyuntik semua kebergantungan, membuat instantiate objek dan memberikannya kembali kepada aliran kawalan utama.
Oleh itu kawalan ke atas suntikan pergantungan diwakilkan sepenuhnya kepada rangka kerja Spring dan tidak berlaku dalam aliran kawalan mel.
Konsep ini dipanggil Inversion of Control (IOC) dan Spring dipanggil Inversion of Control Container atau ringkasnya IOC Container
Atas ialah kandungan terperinci Prinsip Inversi Ketergantungan. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!