Saya tidak tahu mengapa, tetapi saya selalu merasa seperti "selingkuh" ketika saya menggunakan refleksi - mungkin itu karena kinerja hit saya tahu saya ambil.
Sebagian dari saya mengatakan, jika itu adalah bagian dari bahasa yang Anda gunakan dan itu dapat mencapai apa yang Anda coba lakukan, maka mengapa tidak menggunakannya. Bagian lain dari diriku mengatakan, harus ada cara aku bisa melakukan ini tanpa menggunakan refleksi. Saya kira mungkin itu tergantung situasi.
Apa potensi masalah yang perlu saya perhatikan ketika menggunakan refleksi dan seberapa khawatir saya tentang hal itu? Berapa banyak upaya yang perlu dikeluarkan untuk mencoba menemukan solusi yang lebih konvensional?
Jawaban:
Tidak, ini tidak curang - ini adalah cara untuk memecahkan masalah dalam beberapa bahasa pemrograman.
Sekarang, sering kali bukan solusi terbaik (paling bersih, paling sederhana, paling mudah untuk mempertahankan). Jika ada cara yang lebih baik, gunakan yang itu memang. Namun, terkadang tidak ada. Atau jika ada, itu jauh lebih kompleks, melibatkan banyak duplikasi kode dll yang membuatnya tidak layak (sulit untuk mempertahankan dalam jangka panjang).
Dua contoh dari proyek kami saat ini (Jawa):
fieldX
dengan bidang yang sesuai di kelas, dan untuk menginisialisasi yang terakhir. Dalam beberapa kasus, ia dapat membangun kotak dialog GUI sederhana dari properti yang diidentifikasi dengan cepat. Tanpa refleksi, ini akan membutuhkan ratusan baris kode di beberapa aplikasi. Jadi refleksi membantu kami menyusun alat sederhana dengan cepat, tanpa banyak keributan, dan memungkinkan kami untuk fokus pada bagian penting (regresi menguji aplikasi web kami, menganalisis log server, dll.) Daripada yang tidak relevan.Intinya adalah, seperti alat yang kuat, refleksi juga dapat digunakan untuk menembak diri sendiri di kaki. Jika Anda belajar kapan dan bagaimana (tidak) menggunakannya, itu dapat membawa Anda solusi yang elegan dan bersih untuk masalah yang sulit. Jika Anda menyalahgunakannya, Anda dapat mengubah masalah sederhana menjadi kekacauan yang rumit dan jelek.
sumber
if (propName = n) setN(propValue);
, Anda dapat memberi nama (yaitu) tag XML Anda sama dengan properti kode Anda dan menjalankan perulangan di atasnya. Metode ini juga membuatnya lebih mudah untuk menambahkan properti nanti.Itu tidak curang. Tapi itu biasanya ide yang buruk dalam kode produksi untuk setidaknya alasan berikut:
Saya sarankan membatasi penggunaan refleksi untuk kasus-kasus berikut:
Dalam semua kasus lainnya, saya sarankan mencari pendekatan yang menghindari refleksi. Menentukan antarmuka dengan metode yang sesuai dan menerapkannya pada set kelas yang Anda ingin memanggil metode biasanya cukup untuk menyelesaikan sebagian besar kasus sederhana.
sumber
Refleksi hanyalah bentuk lain dari pemrograman meta, dan sama validnya, dengan parameter berbasis tipe yang Anda lihat dalam kebanyakan bahasa saat ini. Refleksi sangat kuat dan generik, dan program reflektif adalah tingkat tinggi pemeliharaan (bila digunakan dengan benar, tentu saja) dan lebih daripada program berorientasi objek atau prosedur murni. Ya, Anda membayar harga kinerja - tetapi dengan senang hati saya akan pergi untuk program yang lebih lambat yang lebih dapat dipertahankan dalam banyak, atau bahkan sebagian besar, kasus.
sumber
Tentunya semua tergantung pada apa yang ingin Anda capai.
Sebagai contoh, saya menulis aplikasi pemeriksa media yang menggunakan injeksi ketergantungan untuk menentukan jenis media apa (file MP3 atau file JPEG) untuk diperiksa. Shell perlu menampilkan kotak yang berisi informasi terkait untuk masing-masing jenis, tetapi tidak memiliki pengetahuan tentang apa yang akan ditampilkan. Ini didefinisikan dalam majelis yang membaca jenis media itu.
Karena itu saya harus menggunakan refleksi untuk mendapatkan jumlah kolom untuk ditampilkan dan jenis serta namanya sehingga saya dapat mengatur kisi dengan benar. Itu juga berarti bahwa saya dapat memperbarui perpustakaan yang disuntikkan (atau membuat yang baru) tanpa mengubah kode atau file konfigurasi lainnya.
Satu-satunya cara lain adalah memiliki file konfigurasi yang perlu diperbarui ketika saya mengganti jenis media yang sedang diperiksa. Ini akan memperkenalkan titik kegagalan lain untuk aplikasi.
sumber
Refleksi adalah alat yang luar biasa jika Anda seorang penulis perpustakaan , dan karenanya tidak memiliki pengaruh terhadap data yang masuk. Kombinasi dari refleksi dan meta-pemrograman dapat memungkinkan perpustakaan Anda untuk bekerja secara lancar dengan penelepon yang sewenang-wenang, tanpa mereka harus melewati rintangan pembuatan kode dll.
Saya mencoba untuk mencegah refleksi dalam kode aplikasi , meskipun; pada lapisan aplikasi Anda harus menggunakan metafora yang berbeda - antarmuka, abstraksi, enkapsulasi dll.
sumber
Refleksi fantastis untuk membangun alat untuk pengembang.
Karena memungkinkan lingkungan build Anda untuk memeriksa kode dan berpotensi menghasilkan alat yang tepat untuk memanipulasi / init memeriksa kode.
Sebagai teknik pemrograman umum, ini bisa bermanfaat tetapi lebih rapuh dari yang dibayangkan kebanyakan orang.
Salah satu pengembangan yang digunakan untuk refleksi (IMO) adalah membuat penulisan pustaka streaming generik menjadi sangat sederhana (selama deskripsi kelas Anda tidak pernah berubah (maka itu menjadi solusi yang sangat rapuh)).
sumber
Penggunaan refleksi sering berbahaya dalam bahasa OO jika tidak digunakan dengan penuh kesadaran.
Saya telah kehilangan hitungan berapa banyak pertanyaan buruk yang saya lihat di situs StackExchange di mana
Berikut adalah contoh tipikal.
Sebagian besar titik OO adalah itu
Jika pada titik mana pun dalam kode Anda, titik 2 tidak valid untuk objek yang telah Anda lewati maka satu atau lebih dari ini adalah benar
Pengembang yang kurang terampil sama sekali tidak mendapatkan ini dan percaya bahwa mereka dapat lulus apa pun di bagian mana pun dari kode mereka dan melakukan apa yang mereka inginkan dari serangkaian kemungkinan (hard-coded) kemungkinan. Idiot ini menggunakan refleksi banyak .
Untuk bahasa OO, refleksi seharusnya hanya diperlukan dalam aktivitas meta (pemuat kelas, injeksi ketergantungan dll). Dalam konteks tersebut, refleksi diperlukan karena Anda menyediakan layanan generik untuk membantu manipulasi / konfigurasi kode yang tidak Anda ketahui tentang alasan yang baik dan sah. Dalam hampir semua situasi lain, jika Anda ingin melakukan refleksi maka Anda melakukan sesuatu yang salah dan Anda perlu bertanya pada diri sendiri mengapa potongan kode ini tidak cukup tahu tentang objek yang telah diteruskan ke sana.
sumber
Alternatif, dalam kasus di mana domain dari kelas yang direfleksikan didefinisikan dengan baik, adalah menggunakan refleksi bersama dengan metadata lain untuk menghasilkan kode , alih-alih menggunakan refleksi pada saat runtime. Saya melakukan ini menggunakan FreeMarker / FMPP; ada banyak alat lain untuk dipilih. Keuntungannya adalah Anda berakhir dengan kode "nyata" yang dapat dengan mudah di-debug, dll.
Bergantung pada situasinya, ini dapat membantu Anda membuat kode lebih cepat - atau hanya banyak mengasapi kode. Ini menghindari kerugian refleksi:
disebutkan sebelumnya.
Jika refleksi terasa seperti selingkuh, itu mungkin karena Anda mendasarkannya pada banyak dugaan yang tidak Anda yakini, dan usus Anda memperingatkan Anda bahwa ini berisiko. Pastikan untuk menyediakan cara untuk meningkatkan metadata yang melekat dalam refleksi dengan metadata Anda sendiri, di mana Anda dapat menggambarkan semua kebiasaan dan kasus khusus dari kelas dunia nyata yang mungkin Anda temui.
sumber
Itu tidak curang, tetapi seperti alat apa pun, itu harus digunakan untuk apa yang dimaksudkan untuk dipecahkan. Refleksi, menurut definisi, memungkinkan Anda untuk memeriksa dan memodifikasi kode melalui kode; jika itu yang perlu Anda lakukan, maka refleksi adalah alat untuk pekerjaan itu. Refleksi adalah semua tentang meta-code: Kode yang menargetkan kode (bukan kode biasa, yang menargetkan data).
Contoh penggunaan refleksi yang baik adalah kelas antarmuka layanan web generik: Desain tipikal adalah memisahkan implementasi protokol dari fungsionalitas payload. Jadi, Anda memiliki satu kelas (sebut saja
T
) yang mengimplementasikan muatan Anda, dan kelas lain yang mengimplementasikan protokol (P
).T
cukup mudah: untuk setiap panggilan yang ingin Anda lakukan, cukup tulis satu metode yang melakukan apa pun yang seharusnya dilakukan.P
Namun, perlu memetakan panggilan layanan web ke panggilan metode. Membuat pemetaan ini generik diinginkan, karena menghindari redundansi, dan membuatnyaP
sangat dapat digunakan kembali. Reflection menyediakan sarana untuk memeriksa kelasT
saat runtime dan memanggil metode-metodenya berdasarkan string yang diteruskan keP
dalam protokol layanan web, tanpa pengetahuan kompilasi waktu dari kelasT
. Menggunakan aturan 'kode tentang kode', orang dapat berargumen bahwa kelasP
memiliki kode di kelasT
sebagai bagian dari datanya.Namun.
Refleksi juga memberi Anda alat untuk mengatasi pembatasan sistem tipe bahasa - secara teoritis, Anda bisa melewati semua parameter sebagai tipe
object
, dan memanggil metode mereka melalui refleksi. Voa, bahasa yang seharusnya menegakkan disiplin pengetikan statis yang kuat sekarang berperilaku seperti bahasa yang diketik secara dinamis dengan pengikatan yang terlambat, hanya saja sintaksanya jauh lebih rumit. Setiap contoh dari pola semacam itu yang saya lihat sejauh ini merupakan peretasan yang kotor, dan selalu, solusi dalam sistem jenis bahasa akan mungkin, dan itu akan lebih aman, lebih elegan, dan lebih efisien dalam segala hal .Ada beberapa pengecualian, seperti kontrol GUI yang dapat terikat data ke berbagai jenis sumber data yang tidak terkait; mengamanatkan bahwa data Anda mengimplementasikan antarmuka tertentu supaya Anda dapat mengikat data itu tidak realistis, dan tidak ada programmer yang menerapkan adaptor untuk setiap jenis sumber data. Dalam hal ini, menggunakan refleksi untuk mendeteksi jenis sumber data dan menyesuaikan pengikatan data adalah pilihan yang lebih berguna.
sumber
Satu masalah yang kami miliki dengan Reflection adalah ketika kami menambahkan Kebingungan ke dalam campuran. Semua kelas mendapatkan nama baru dan tiba-tiba memuat kelas atau fungsi dengan namanya berhenti berfungsi.
sumber
Itu sangat tergantung. Contoh dari sesuatu yang akan sulit dilakukan tanpa refleksi adalah mereplikasi ObjectListView . Itu juga menghasilkan kode IL on the fly.
sumber
Refleksi adalah metode utama untuk menciptakan sistem berbasis konvensi. Saya tidak akan terkejut menemukan itu sedang digunakan di sebagian besar kerangka kerja MVC. Ini adalah komponen utama dalam ORM. Kemungkinannya, Anda sudah menggunakan komponen yang dibangun dengannya setiap hari.
Alternatif untuk penggunaan semacam itu adalah konfigurasi, yang memiliki kekurangannya sendiri.
sumber
Refleksi dapat mencapai hal-hal yang tidak bisa dilakukan secara praktis sebaliknya.
Misalnya, pertimbangkan cara mengoptimalkan kode ini:
Ada pukulan uji mahal di tengah loop dalam, tetapi mengekstraknya membutuhkan penulisan ulang loop sekali untuk setiap operator. Refleksi memungkinkan kita untuk mendapatkan kinerja yang setara dengan mengekstraksi tes itu, tanpa mengulangi loop selusin kali (dan dengan demikian mengorbankan pemeliharaan). Cukup hasilkan dan kompilasi loop yang Anda butuhkan dengan cepat.
Saya sebenarnya telah melakukan optimasi ini , walaupun situasinya sedikit lebih rumit, dan hasilnya luar biasa. Urutan peningkatan besar dalam kinerja dan lebih sedikit baris kode.
(Catatan: Saya awalnya mencoba yang setara dengan melewatkan di Func alih-alih char, dan itu sedikit lebih baik, tetapi hampir tidak mencapai refleksi 10x.)
sumber
Tidak mungkin itu curang ... Sebaliknya, ini memberdayakan server aplikasi untuk menjalankan kelas yang dibuat oleh pengguna dengan nama pilihan mereka, karenanya memberikan fleksibilitas kepada pengguna, bukan menipu mereka.
Dan jika Anda ingin melihat kode file .class apa saja (di Jawa) maka ada beberapa dekompiler yang tersedia secara gratis!
sumber