Kami menerapkan adaptor untuk Jaxen (perpustakaan XPath untuk Java) yang memungkinkan kami untuk menggunakan XPath untuk mengakses model data aplikasi kami.
Ini dilakukan dengan mengimplementasikan kelas yang memetakan string (diteruskan kepada kami dari Jaxen) ke dalam elemen model data kami. Kami memperkirakan kami akan membutuhkan sekitar 100 kelas dengan total perbandingan 1000 string.
Saya pikir cara terbaik untuk melakukan ini adalah pernyataan if / else sederhana dengan string yang ditulis langsung ke dalam kode - daripada mendefinisikan setiap string sebagai sebuah konstanta. Sebagai contoh:
public Object getNode(String name) {
if ("name".equals(name)) {
return contact.getFullName();
} else if ("title".equals(name)) {
return contact.getTitle();
} else if ("first_name".equals(name)) {
return contact.getFirstName();
} else if ("last_name".equals(name)) {
return contact.getLastName();
...
Namun saya selalu diajarkan bahwa kita seharusnya tidak menanamkan nilai string secara langsung ke dalam kode, tetapi membuat konstanta string sebagai gantinya. Itu akan terlihat seperti ini:
private static final String NAME = "name";
private static final String TITLE = "title";
private static final String FIRST_NAME = "first_name";
private static final String LAST_NAME = "last_name";
public Object getNode(String name) {
if (NAME.equals(name)) {
return contact.getFullName();
} else if (TITLE.equals(name)) {
return contact.getTitle();
} else if (FIRST_NAME.equals(name)) {
return contact.getFirstName();
} else if (LAST_NAME.equals(name)) {
return contact.getLastName();
...
Dalam hal ini saya pikir itu ide yang buruk. Konstanta hanya akan digunakan sekali, dalam getNode()
metode ini. Menggunakan string secara langsung sama mudahnya dibaca dan dipahami dengan menggunakan konstanta, dan menyelamatkan kita menulis setidaknya seribu baris kode.
Jadi apakah ada alasan untuk mendefinisikan konstanta string untuk penggunaan tunggal? Atau apakah dapat diterima untuk menggunakan string secara langsung?
PS. Sebelum ada yang menyarankan menggunakan enum, kami membuat prototipe, tetapi konversi enum 15 kali lebih lambat dari perbandingan string sederhana sehingga tidak dipertimbangkan.
Kesimpulan: Jawaban di bawah ini memperluas cakupan pertanyaan ini di luar konstanta string, jadi saya punya dua kesimpulan:
- Mungkin OK untuk menggunakan string secara langsung daripada konstanta string dalam skenario ini, tetapi
- Ada beberapa cara untuk menghindari penggunaan string sama sekali, yang mungkin lebih baik.
Jadi saya akan mencoba teknik pembungkus yang menghindari string sepenuhnya. Sayangnya kami tidak dapat menggunakan pernyataan saklar string karena kami belum berada di Java 7. Namun pada akhirnya, saya pikir jawaban terbaik bagi kami adalah mencoba setiap teknik dan mengevaluasi kinerjanya. Kenyataannya adalah bahwa jika satu teknik jelas lebih cepat maka kita mungkin akan memilihnya terlepas dari keindahan atau kepatuhannya pada konvensi.
sumber
switch
label. Gunakan sakelar alih-alihif
riam.Jawaban:
Coba ini. Refleksi awal tentu mahal, tetapi jika Anda akan menggunakannya berkali-kali, yang saya pikir Anda akan lakukan, ini pasti merupakan solusi yang lebih baik apa yang Anda usulkan. Saya tidak suka menggunakan refleksi, tetapi saya mendapati diri saya menggunakannya ketika saya tidak suka alternatif untuk refleksi. Saya pikir ini akan menyelamatkan tim Anda banyak sakit kepala, tetapi Anda harus melewati nama metode (dalam huruf kecil).
Dengan kata lain, alih-alih memberikan "nama", Anda akan memberikan "nama lengkap" karena nama metode get adalah "getFullName ()".
Jika Anda perlu mengakses data yang terkandung dalam anggota kontak, Anda dapat mempertimbangkan membangun kelas pembungkus untuk kontak yang memiliki semua metode untuk mengakses informasi yang diperlukan. Ini juga akan berguna untuk menjamin bahwa nama-nama bidang akses akan selalu tetap sama (yaitu jika kelas wrapper memiliki getFullName () dan Anda memanggil dengan nama lengkap, itu akan selalu berfungsi bahkan jika kontak getFullName () telah diganti namanya - itu akan menyebabkan kesalahan kompilasi sebelum Anda dapat melakukannya).
Solusi ini telah menyelamatkan saya beberapa kali, yaitu ketika saya ingin memiliki representasi data tunggal untuk digunakan dalam jsf datatables dan ketika data itu perlu diekspor ke dalam laporan menggunakan jasper (yang tidak menangani aksesor objek yang rumit dengan baik dalam pengalaman saya) .
sumber
.invoke()
, karena tidak menghilangkan konstanta string sepenuhnya. Saya tidak begitu tertarik pada refleksi runtime untuk mengatur peta, meskipun mungkin mengeksekusigetMethodMapping()
dalam sebuahstatic
blok akan baik-baik saja sehingga hal itu terjadi pada startup bukannya setelah sistem berjalan.Jika mungkin gunakan Java 7 yang memungkinkan Anda untuk menggunakan Strings dalam
switch
pernyataan.Dari http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html
Saya belum mengukur, tetapi saya percaya bahwa pernyataan switch mengkompilasi ke tabel lompatan alih-alih daftar panjang perbandingan. Ini harus lebih cepat.
Mengenai pertanyaan Anda yang sebenarnya: Jika Anda hanya menggunakannya sekali Anda tidak perlu membuatnya menjadi konstanta. Namun pertimbangkan bahwa konstanta dapat didokumentasikan dan muncul di Javadoc. Ini mungkin penting untuk nilai string non-sepele.
sumber
Jika Anda akan mempertahankan ini (membuat segala perubahan nontrivial yang pernah ada), saya mungkin benar-benar mempertimbangkan untuk menggunakan semacam pembuatan kode berbasis anotasi (mungkin melalui CGLib ) atau bahkan hanya sebuah skrip yang menulis semua kode untuk Anda. Bayangkan jumlah kesalahan pengetikan dan kesalahan yang dapat merambah dengan pendekatan yang Anda pertimbangkan ...
sumber
object.getAddress().getCountry()
) yang sulit untuk diwakili dengan anotasi. Perbandingan string if / else tidak cantik, tetapi mereka cepat, fleksibel, mudah dimengerti dan mudah untuk unit test.Saya masih akan menggunakan konstanta yang didefinisikan di bagian atas kelas Anda. Itu membuat kode Anda lebih mudah dikelola karena lebih mudah untuk melihat apa yang dapat diubah di lain waktu (jika perlu). Misalnya,
"first_name"
bisa menjadi"firstName"
beberapa waktu kemudian.sumber
Jika penamaan Anda konsisten (alias
"some_whatever"
selalu dipetakan kegetSomeWhatever()
), Anda bisa menggunakan refleksi untuk menentukan dan menjalankan metode get.sumber
Saya kira, pemrosesan anotasi bisa menjadi solusinya, bahkan tanpa anotasi. Itu hal yang dapat menghasilkan semua kode membosankan untuk Anda. Kelemahannya adalah Anda akan mendapatkan kelas N yang dihasilkan untuk kelas model N. Anda juga tidak dapat menambahkan apa pun ke kelas yang ada, tetapi menulis sesuatu seperti
sekali per kelas seharusnya tidak menjadi masalah. Atau, Anda dapat menulis sesuatu seperti
dalam superclass umum.
Anda dapat menggunakan refleksi alih-alih pemrosesan anotasi untuk pembuatan kode. Kelemahannya adalah Anda memerlukan kode Anda untuk dikompilasi sebelum Anda dapat menggunakan refleksi di atasnya. Ini berarti Anda tidak dapat mengandalkan kode yang dihasilkan di kelas model Anda, kecuali jika Anda menghasilkan beberapa bertopik.
Saya juga akan mempertimbangkan penggunaan refleksi secara langsung. Tentu, refleksi itu lambat, tetapi mengapa lambat? Itu karena harus melakukan semua hal yang perlu Anda lakukan, misalnya, aktifkan nama bidang.
sumber