Baru -baru ini, saya selalu terpapar prinsip atau pola pemrograman seperti IOC (inversi kontrol) dan DI (injeksi ketergantungan), yang merupakan inti dari Java Frameworks Spring yang terkenal, struts, dll. Sebagai tanggapan terhadap hal ini, saya memeriksa berbagai item di Wikipedia dan meminjam buku -buku yang relevan dari perpustakaan. Setelah membacanya, saya memiliki beberapa pengertian. Sekarang saya akan menggabungkan penjelasan dalam buku dan pemrosesan saya sendiri dan menyelesaikannya sebagai berikut:
EG1
Deskripsi Masalah:
Kembangkan sistem yang dapat menghasilkan laporan dalam format Excel atau PDF sesuai dengan persyaratan yang berbeda, seperti laporan harian, laporan bulanan, dll.
Larutan:
Menurut prinsip "pemrograman berorientasi antarmuka", antarmuka dan implementasi harus dipisahkan, yaitu fungsi menghasilkan laporan diekstraksi ke dalam pelapor antarmuka umum, dan dua implementasi yang menghasilkan laporan Excel dan PDF dalam format Excel dan PDF disediakan. Klien kemudian memperoleh fungsi pencetakan laporan yang sesuai melalui Layanan Laporan Laporan Layanan.
Metode Implementasi:
Menurut hal di atas, diagram kelas berikut diperoleh:
Implementasi Kode:
Antarmuka ReportGenerator {public void menghasilkan (tabel tabel); } kelas Excelgenerator mengimplementasikan ReportGenerator {public void menghasilkan (tabel tabel) {System.out.println ("Hasilkan laporan Excel ..."); }} kelas PDFGenerator mengimplementasikan ReportGenerator {public void menghasilkan (tabel tabel) {System.out.println ("Hasilkan laporan PDF ..."); }} class Reportservice {// Bertanggung jawab untuk membuat generator laporan untuk kebutuhan spesifik Generator ReportGenerator Pribadi = PDFGenerator baru (); // Generator ReportGenerator Statis Pribadi = Excelgenerator baru (); public void getdailyreport (tanggal tanggal) {table.setDate (tanggal); // ... generator.generate (tabel); } public void getMonthlyreport (bulan bulan) {Table.setMonth (bulan); // ... generator.generate (tabel); }} klien kelas publik {public static void main (string [] args) {Reportservice Reportservice = new ReportService (); Reportservice.getdailyreport (tanggal baru ()); //ReportService.GetMonthlyreport( tanggal baru ()); }}
EG2
Deskripsi Masalah:
Seperti yang ditunjukkan dalam komentar dalam kode di atas, generator laporan spesifik dibuat oleh hard-coded secara internal di kelas ReportService, sehingga Laporan Reports telah secara langsung mengandalkan PDFGenerator atau Excelgenerator, dan kopling ketat yang jelas ini harus dieliminasi.
Solusi: Memperkenalkan wadah untuk memperkenalkan manajer perantara, yaitu, wadah (wadah), yang secara seragam mengelola objek yang terlibat dalam sistem pelaporan (di sini adalah komponen, kami menyebutnya kacang), termasuk layanan laporan dan berbagai XXGenerator. Di sini Anda menggunakan instance hashmap dalam bentuk pasangan nilai kunci untuk menyimpan kacang ini.
Metode Implementasi:
Diagram kelas diperoleh sebagai berikut:
Implementasi Kode:
wadah kelas {// simpan berbagai komponen yang diperlukan dalam peta statis peta private value peta private <string, objek> kacang; wadah publik () {beans = hashmap baru <string, objek> (); // Buat dan simpan laporan Generator Laporan Khusus ReportGenerator ReportGenerator = new PDFGenerator (); beans.put ("ReportGenerator", ReportGenerator); // Dapatkan dan kelola referensi ReportService ReportService ReportService = new Reportservice (); beans.put ("Reportservice", Reportservice); } objek statis publik getBean (ID String) {return beans.get (id); }} Class Reportservice {// Hilangkan hubungan kopling ketat dan gantilah dengan wadah // private static ReportGenerator Generator = new PDFGenerator (); Generator Generator Report Generator Pribadi = (ReportGenerator) Container.getBean ("ReportGenerator"); public void getdailyreport (tanggal tanggal) {table.setDate (tanggal); generator.generate (tabel); } public void getMonthlyreport (bulan bulan) {Table.setMonth (bulan); generator.generate (tabel); }} klien kelas publik {public static void main (string [] args) {container container = new container (); ReportService Reportservice = (ReportService) container.getbean ("Reportservice"); Reportservice.getdailyreport (tanggal baru ()); //ReportService.GetMonthlyreport( tanggal baru ()); }}
Bagan waktu kira -kira sebagai berikut:
Memengaruhi:
Seperti yang ditunjukkan di atas, ReportService tidak lagi secara langsung terkait dengan ReportGenerator spesifik. Ini telah menggunakan wadah untuk mengisolasi antarmuka dan implementasi, meningkatkan reusability kacang komponen sistem. Saat ini, Anda juga dapat menggunakan file konfigurasi untuk mendapatkan definisi komponen spesifik dalam wadah secara real time.
EG3
Deskripsi Masalah:
Namun, jika Anda melihat diagram kelas di atas, mudah untuk menemukan bahwa ada hubungan dua arah antara layanan laporan dan wadah, dan mereka memiliki ketergantungan timbal balik. Dan, jika Anda ingin menggunakan kembali Reportservice, itu juga secara langsung tergantung pada logika pencarian spesifik dari satu wadah. Jika wadah lain memiliki mekanisme pencarian komponen yang berbeda (seperti JNDI), menggunakan kembali layanan laporan saat ini berarti bahwa logika pencarian internal dari wadah perlu dimodifikasi.
Solusi: Memperkenalkan Layanan Layanan
Pengenalan ulang Locator Layanan Lapisan Tidak Langsung digunakan untuk menyediakan antarmuka untuk logika pencarian komponen. Silakan lihat deskripsi di Wikipedia atau deskripsi oleh Java EE 1 dan 2. Ini akan memungkinkan kemungkinan isolasi perubahan yang mungkin.
Metode Implementasi:
Diagram kelas adalah sebagai berikut:
Implementasi Kode:
// Dalam aplikasi aktual, Anda dapat menggunakan antarmuka untuk menyediakan kelas interface terpadu ServiceLocator {private static container wadah = wadah baru (); Public Static ReportGenerator getReportGenerator () {return (ReportGenerator) container.getBean ("ReportGeneraator"); }} class Reportservice {private ReportGenerator ReportGenerator = serviceLocator.getReportGenerator (); // ...}EG4
Deskripsi Masalah:
Namun, apakah itu memperkenalkan wadah atau menggunakan Layanan Layanan, ReportService 'aktif' dalam mencari dan membuat komponen tertentu, yang berarti bahwa sebagai pelanggan, layanan laporan harus jelas tentang apa yang dibutuhkan, di mana ia dapat diperoleh, dan bagaimana hal itu dapat diperoleh. Tiba -tiba detail logis spesifik harus ditambahkan karena apa, di mana, dan bagaimana.
Misalnya, dalam metode implementasi sebelumnya dari 'memperkenalkan wadah', ada kode berikut:
Class Reportservice {// Hilangkan hubungan kopling yang ketat dan gantilah dengan wadah // private static Reportgenerator generator = new PDFGenerator (); // Temukan Container ReportGenerator Private = (ReportGenerator) .getBean ("ReportGenerator");
Dalam metode implementasi 'memperkenalkan Layanan Layanan', ada kode berikut:
kelas serviceLocator {privatestatic container wadah = wadah baru (); PublicStatic ReporTenerator getReportGenerator () {// Ini masih container.getBean (), hanya delegasi yang digunakan pengembalian (ReportGenerator) container.getBean ("ReportGeneraator"); }} Class Reportservice {// ReportService Pada akhirnya, masih 'secara aktif' mencari dan mendelegasikan ke ServiceLocator Private Reporgenerator ReportGenerator = ServiceLocator.GetReportGenerator (); }
Larutan:
Dalam hal ini, mengubah 'aktif' menjadi 'pasif' tidak diragukan lagi akan mengurangi pengetahuan internal Laporan Laporan (mis. Logika komponen menemukan). Menurut prinsip inversi kontrol (IOC), tarikan ini (tarik, aktif) dikonversi menjadi mode dorong (dorong, pasif).
Misalnya, langganan RSS yang biasanya kami gunakan adalah aplikasi push, yang menghemat kerumitan masuk ke situs favorit kami beberapa kali sehari untuk secara aktif mendapatkan pembaruan artikel.
Injeksi ketergantungan (DI) mencapai penerimaan pasif semacam ini dan mengurangi masalah pelanggan (di sini, Laporan Laporan) sendiri yang mengandung logika kompleks dan mengetahui terlalu banyak.
Metode Implementasi:
Karena kami ingin menjadi resepsi 'pasif', kami harus kembali ke contoh wadah tanpa menggunakan mode Layanan Layanan. Diagram kelas yang dimodifikasi diperoleh dari ini sebagai berikut:
Diagram kelas asli adalah sebagai berikut. Anda dapat memeriksanya dan memperhatikan permintaan komentar:
Implementasi Kode:
Untuk memungkinkan contoh disusun dan dijalankan, dan menggunakan hasil berjalan dari kode pelacakan untuk secara eksplisit instantiate seluruh diagram kelas dan bekerja sama satu sama lain secara berurutan, banyak pernyataan cetak bernomor dan dua kelas yang tidak signifikan ditambahkan ke konstruktor masing -masing kelas, yang sedikit menghina, sebagai berikut:
impor java.util.date; import java.util.hashmap; impor java.util.map; // Untuk dapat dikompilasi dan dijalankan, ada dua kelas yang lebih tidak penting. Bulan kelas {} Tabel kelas {publicVoid setDate (tanggal tanggal) {} publicVoid setMonth (bulan bulan) {}} // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- dari Excelgenerator ... "); } publicVoid menghasilkan (tabel tabel) {System.out.println ("Hasilkan Laporan Excel ..."); }} class PDFGenerator mengimplementasikan ReportGenerator {Public PDFGenerator () {System.out.println ("2 ... Mulai inisialisasi PDFGenerator ..."); } publicVoid menghasilkan (tabel tabel) {System.out.println ("Hasilkan laporan PDF ..."); }} // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Dapatkan dan Kelola Referensi ReportService Reportservice ReportService = New Reportservice (); // Suntikkan contoh laporan spesifik yang dibuat di atas Reportservice.setreportgenerator (ReportGenerator); beans.put ("Reportservice", Reportservice); System.out.println ("5 ... Wadah Inisialisasi Akhir ..."); } objek publicstatic getBean (ID String) {System.out.println ("Last Get Service Component ... getBean () ->" + id + "..."); returnbeans.get (id); }} class Reportservice {// private static Reportgenerator generator = new PDFGenerator (); // Hilangkan hubungan kopling ketat di atas dan ganti dengan wadah // private Reportgenerator Generator = (ReportGenerator) Container // .getBean ("ReportGenerator"); // Hapus pencarian "aktif" di atas dan sediakan bidang pribadi untuk menyimpan objek eksternal yang disuntikkan generator pelapor privat; // Suntikkan PublicVoid dari luar dalam setter cara setReportGenerator (Generator ReportGenerator) {System.out.println ("4 ... Mulai Suntikan ReportGenerator ..."); this.generator = generator; } tabel tabel pribadi = tabel baru (); Public Reportservice () {System.out.println ("3 ... Mulai Inisialisasi ReportService ..."); } publicVoid getdailyreport (tanggal tanggal) {table.setDate (tanggal); generator.generate (tabel); } publicVoid getMonthlyreport (bulan bulan) {Table.setMonth (bulan); generator.generate (tabel); }} publicclass klien {publicstaticvoid main (string [] args) {// inisialisasi wadah wadah baru (); Laporan Laporan Laporan Laporan = (ReportService) Container .getBean ("Reportservice"); Reportservice.getdailyreport (tanggal baru ()); // Reportservice.getmonthlyreport (tanggal baru ()); }}
Hasil Menjalankan:
1 ... Mulai Wadah Inisialisasi ... 2 ... Mulai Inisialisasi PDFGenerator ... 3 ... Mulai Inisialisasi Laporan Laporan ... 4 ... Mulai Suntikan ReportGenerator ... 5 ... Wadah Inisialisasi Akhir ... Akhirnya Dapatkan Komponen Layanan ... GetBean () -> ReportService ... menghasilkan laporan PDF ...
Melihat:
1. Menurut urutan pencetakan hasil yang dijalankan di atas, dapat dilihat bahwa angka -angka spesifik yang ditambahkan ke kode masuk akal, yang mensimulasikan proses eksekusi program, sehingga tidak lagi menggambar diagram urutan.
2. Perhatikan bahwa penggunaan IOC dan DI dalam contoh ini didasarkan pada ReportService sebagai klien (mis. Komponen Demander), dan kode uji di kelas klien () dalam kode adalah pengguna akhir dari komponen layanan, tetapi yang dibutuhkan bukan komponen, tetapi layanan yang dimiliki komponen.
3. Faktanya, dalam klip kotak Spring, menginisialisasi wadah jelas bukan apa yang harus dilakukan oleh klien pengguna akhir, itu harus dimulai sebelumnya oleh penyedia layanan.
4. Di Klien Pengguna Akhir, kami masih menggunakan Container.getbean ("Reportservice") untuk mendapatkan komponen layanan yang telah dipakai dalam konstruktor kontainer terlebih dahulu. Dalam aplikasi tertentu, komponen layanan yang tersedia biasanya digunakan ke server menggunakan XML dan file konfigurasi lainnya, dan kemudian file konfigurasi dibaca oleh wadah dan dikombinasikan dengan teknologi refleksi untuk membuat dan menyuntikkan komponen layanan tertentu.
menganalisa:
Sebelumnya, ReportService secara aktif meminta komponen layanan dari wadah, tetapi sekarang secara pasif menunggu komponen layanan container injection (inject, yaitu, push). Kontrol jelas ditransfer dari modul yang mendasarinya (Reportservice adalah Demander komponen) ke modul tingkat tinggi (wadah adalah penyedia komponen), yaitu, kontrol terbalik.