Saya mengambil satu set tupel dari basis data, dan meletakkannya di peta. Permintaan basis data itu mahal.
Tidak ada urutan alami yang jelas dari elemen-elemen di peta, tetapi urutan penyisipan tetap penting. Menyortir peta akan menjadi operasi yang berat, jadi saya ingin menghindari melakukan itu, mengingat bahwa hasil kueri sudah diurutkan seperti yang saya inginkan. Oleh karena itu, saya hanya menyimpan hasil kueri ke dalam LinkedHashMap
, dan mengembalikan peta dari metode DAO:
public LinkedHashMap<Key, Value> fetchData()
Saya memiliki metode processData
yang harus melakukan beberapa pemrosesan pada peta - memodifikasi beberapa nilai, menambahkan beberapa kunci / nilai baru. Ini didefinisikan sebagai
public void processData(LinkedHashMap<Key, Value> data) {...}
Namun, beberapa linter (Sonar dll) mengeluh bahwa Jenis 'data' harus berupa antarmuka seperti 'Peta' daripada implementasi "LinkedHashMap" ( squid S1319 ).
Jadi pada dasarnya itu mengatakan bahwa saya seharusnya
public void processData(Map<Key, Value> data) {...}
Tapi saya ingin tanda tangan metode mengatakan bahwa urutan peta penting - penting untuk algoritma di processData
- sehingga metode saya tidak lulus sembarang peta acak.
Saya tidak ingin menggunakan SortedMap
, karena itu (dari javadoc ofjava.util.SortedMap
) "dipesan sesuai dengan urutan kuncinya, atau oleh Pembanding yang biasanya disediakan pada waktu pembuatan peta yang diurutkan."
Kunci saya tidak memiliki urutan alami , dan membuat Pembanding untuk tidak melakukan apa pun tampaknya bertele-tele.
Dan saya masih ingin itu menjadi peta, untuk mengambil keuntungan dari put
menghindari duplikat kunci dll. Jika tidak, data
bisa saja a List<Map.Entry<Key, Value>>
.
Jadi bagaimana saya mengatakan bahwa metode saya menginginkan peta yang sudah diurutkan ? Sayangnya, tidak ada java.util.LinkedMap
antarmuka, atau saya akan menggunakannya.
sumber
if you are new to programming and stumble upon this answer, don't think this allows you to go against best practice because it doesn't.
- Saran yang bagus, jika ada yang namanya "praktik terbaik." Saran yang lebih baik: pelajari cara membuat keputusan yang tepat. Ikuti latihan jika itu masuk akal, tetapi biarkan alat dan otoritas memandu proses berpikir Anda, bukan mendikte itu.Anda bertengkar tiga hal:
Pertama adalah perpustakaan kontainer Java. Tidak ada dalam taksonomi yang memberi Anda cara untuk menentukan apakah kelas iterate atau tidak dalam urutan yang dapat diprediksi. Tidak ada
IteratesInInsertedOrderMap
antarmuka yang dapat diimplementasikan olehLinkedHashMap
, yang membuat pengecekan tipe (dan penggunaan implementasi alternatif yang berperilaku dengan cara yang sama) tidak mungkin. Itu mungkin karena desain, karena semangatnya adalah bahwa Anda benar-benar seharusnya mampu menangani objek yang berperilaku seperti abstrakMap
.Kedua adalah keyakinan bahwa apa yang dikatakan oleh orang suci Anda harus diperlakukan sebagai Injil dan bahwa mengabaikan apa pun yang dikatakannya adalah buruk. Bertentangan dengan apa yang berlaku untuk praktik yang baik hari ini, peringatan linter seharusnya tidak menjadi hambatan untuk memanggil kode Anda baik. Mereka diminta untuk beralasan tentang kode yang Anda tulis dan menggunakan pengalaman dan penilaian Anda untuk menentukan apakah peringatan itu dibenarkan atau tidak. Peringatan yang tidak dapat dibenarkan adalah alasan mengapa hampir setiap alat analisis statis menyediakan mekanisme untuk mengatakan bahwa Anda telah memeriksa kode, Anda berpikir apa yang Anda lakukan tidak apa-apa dan bahwa mereka tidak boleh mengeluh tentang hal itu di masa depan.
Ketiga, dan ini mungkin dagingnya,
LinkedHashMap
mungkin alat yang salah untuk pekerjaan itu. Peta dimaksudkan untuk akses acak, bukan dipesan. JikaprocessData()
hanya mengulangi catatan secara berurutan dan tidak perlu menemukan catatan lainnya dengan kunci, Anda memaksa implementasi khususMap
untuk melakukan pekerjaan aList
. Di sisi lain, jika Anda membutuhkan keduanya,LinkedHashMap
adalah alat yang tepat karena itu dikenal untuk melakukan apa yang Anda inginkan dan Anda lebih dari dibenarkan dalam membutuhkannya.sumber
OrderedMap
, saya bisa saja mengatakannyaUniqueList
. Selama itu adalah semacam koleksi dengan urutan iterasi yang ditentukan, yang menimpa duplikat pada sisipan.Set
dari kunci-kunci tersebut saat Anda sedang membangun daftar sebagai cara untuk menemukannya.processData
memodifikasi peta, mengganti beberapa nilai, memperkenalkan beberapa kunci / nilai baru. JadiprocessData
dapat memperkenalkan duplikat jika beroperasi pada sesuatu selain aMap
.UniqueList
(atauOrderedUniqueList
) dan menggunakannya. Ini sangat mudah, dan membuat penggunaan yang Anda maksudkan menjadi lebih jelas.Jika semua yang Anda peroleh
LinkedHashMap
adalah kemampuan untuk menimpa duplikat, tetapi Anda benar-benar menggunakannya sebagaiList
, maka saya sarankan lebih baik untuk mengkomunikasikan penggunaan itu denganList
implementasi kustom Anda sendiri . Anda dapat mendasarkannya pada kelas koleksi Java yang ada dan cukup menimpa apa punadd
danremove
metode untuk memperbarui toko dukungan Anda dan melacak kunci untuk memastikan keunikan. Memberi ini nama yang khas sepertiProcessingList
akan memperjelas bahwa argumen yang disajikan untukprocessData
metode Anda perlu ditangani dengan cara tertentu.sumber
ProcessingList
sebagai alias untukLinkedHashMap
- Anda selalu dapat memutuskan untuk menggantinya dengan yang lain nanti, selama Anda menjaga antarmuka publik tetap utuh.Saya mendengar Anda berkata, "Saya memiliki satu bagian dari sistem saya yang menghasilkan LinkedHashMap, dan di bagian lain dari sistem saya, saya hanya perlu menerima objek LinkedHashMap yang diproduksi oleh bagian pertama, karena yang diproduksi oleh beberapa proses lain akan menang ' t bekerja dengan benar. "
Itu membuat saya berpikir bahwa masalah di sini sebenarnya adalah Anda mencoba menggunakan LinkedHashMap karena sebagian besar cocok dengan data yang Anda cari, tetapi sebenarnya itu tidak dapat digantikan dengan contoh lain selain yang Anda buat. Apa yang sebenarnya ingin Anda lakukan adalah membuat antarmuka / kelas Anda sendiri yang merupakan bagian pertama Anda buat dan bagian kedua Anda konsumsi. Ini dapat membungkus LinkedHashMap "asli", dan menyediakan pengambil Peta atau mengimplementasikan antarmuka Peta.
Ini sedikit berbeda dari jawaban CandiedOrange, karena saya akan merekomendasikan merangkum Peta asli (dan mendelegasikan panggilan ke sana sesuai kebutuhan) daripada memperpanjangnya. Kadang-kadang ini adalah salah satu perang suci gaya, tetapi jelas bagi saya itu bukan "Peta dengan beberapa hal tambahan", melainkan "Tas saya berisi informasi berguna negara, yang secara internal dapat saya wakili dengan Peta".
Jika Anda memiliki dua variabel yang harus Anda lewati seperti ini, Anda mungkin telah membuat kelas untuk itu tanpa berpikir banyak tentangnya. Tetapi kadang-kadang berguna untuk memiliki kelas bahkan jika itu hanya satu variabel anggota, hanya karena itu hal yang sama secara logis, bukan "nilai" tetapi "hasil operasi saya bahwa saya perlu melakukan sesuatu dengan nanti".
sumber
MyBagOfUsefulInformation
akan memerlukan metode (atau konstruktor) untuk mengisi itu:MyBagOfUsefulInformation.populate(SomeType data)
. Tetapidata
perlu hasil pencarian yang diurutkan. Jadi apa jadinyaSomeType
, jika tidakLinkedHashMap
? Saya tidak yakin saya dapat memecahkan Catch 22 ini.MyBagOfUsefulInformation
dapat dibuat oleh DAO atau apa pun yang menghasilkan data di sistem Anda? Mengapa Anda perlu memaparkan peta yang mendasari sama sekali ke seluruh kode Anda di luar produsen dan konsumen Tas?MyBagOfUsefulInformation
sebagai parameter pada metode DAO: softwareengineering.stackexchange.com/a/360079/52573LinkedHashMap adalah satu-satunya peta java yang memiliki fitur urutan penyisipan yang Anda cari. Jadi membuang Prinsip Pembalikan Ketergantungan itu menggoda dan bahkan mungkin praktis. Pertama, pertimbangkan apa yang harus dilakukan untuk mengikutinya. Inilah yang SOLID akan minta Anda lakukan.
Catatan: ganti nama
Ramdal
dengan nama deskriptif yang mengomunikasikan bahwa konsumen antarmuka ini adalah pemilik antarmuka ini. Yang menjadikannya otoritas yang memutuskan apakah urutan penyisipan penting. Jika Anda hanya menyebut ini,InsertionOrderMap
Anda benar-benar melewatkan intinya.Apakah ini desain besar di depan? Mungkin, tergantung pada seberapa besar kemungkinan Anda berpikir bahwa Anda akan memerlukan implementasi selain itu
LinkedHashMap
. Tetapi jika Anda tidak mengikuti DIP hanya karena itu akan sangat menyakitkan, saya tidak berpikir pelat ketel lebih menyakitkan dari ini. Ini adalah pola yang saya gunakan ketika saya berharap kode yang tidak tersentuh mengimplementasikan antarmuka yang tidak. Bagian yang paling menyakitkan adalah memikirkan nama-nama baik.sumber
Terima kasih atas banyak saran dan makanan yang bagus untuk dipikirkan.
Saya akhirnya memperluas membuat kelas peta baru, membuat
processData
metode contoh:Lalu saya refactored metode DAO sehingga tidak mengembalikan peta, tetapi mengambil
target
peta sebagai parameter:Jadi mengisi
DataMap
dan memproses data sekarang merupakan proses dua langkah, yang baik-baik saja, karena ada beberapa variabel lain yang merupakan bagian dari algoritma, yang berasal dari tempat lain.Ini memungkinkan implementasi Peta saya untuk mengontrol bagaimana entri dimasukkan ke dalamnya, dan menyembunyikan persyaratan pemesanan - sekarang detail implementasi
DataMap
.sumber
Jika Anda ingin berkomunikasi bahwa struktur data yang Anda gunakan ada karena suatu alasan, tambahkan komentar di atas tanda tangan metode. Jika pengembang lain di masa depan menemukan garis kode ini dan memperhatikan peringatan alat, mereka mungkin memperhatikan komentar itu juga dan menahan diri dari "memperbaiki" masalah tersebut. Jika tidak ada komentar, maka tidak ada yang akan menghentikan mereka untuk mengubah tanda tangan.
Menekan peringatan lebih rendah daripada berkomentar dalam pendapat saya, karena penindasan itu sendiri tidak menyatakan alasan mengapa peringatan itu ditekan. Kombinasi penindasan peringatan dan komentar juga akan baik-baik saja.
sumber
Jadi, izinkan saya mencoba memahami konteks Anda di sini:
Sekarang, apa yang sedang Anda lakukan:
Dan inilah kode Anda saat ini:
Saran saya adalah melakukan hal berikut:
Contoh Kode
Saya kira ini akan menghilangkan peringatan Sonar, dan juga menentukan tata letak khusus data yang diperlukan oleh metode pemrosesan.
sumber
MyTupleRepository
dibuat?)Pertanyaan ini sebenarnya adalah banyak masalah dengan model data Anda digulung menjadi satu. Anda harus mulai melepaskan mereka, satu per satu. Solusi yang lebih alami dan intuitif akan keluar saat Anda mencoba menyederhanakan setiap bagian teka-teki.
Masalah 1: Anda tidak dapat bergantung pada Pesanan DB
Deskripsi Anda tentang pengurutan data Anda tidak jelas.
ORDER BY
klausa. Jika bukan karena sepertinya terlalu mahal, program Anda memiliki bug . Database diizinkan untuk mengembalikan hasil dalam urutan apa pun jika Anda tidak menentukannya; Anda tidak dapat bergantung padanya secara acak mengembalikan data dalam urutan hanya karena Anda menjalankan kueri beberapa kali dan terlihat seperti itu. Urutan mungkin berubah karena baris disusun ulang pada disk, atau beberapa dihapus dan yang baru menggantikannya, atau indeks ditambahkan. Anda harus menentukanORDER BY
klausa dari beberapa jenis. Kecepatan tidak ada artinya tanpa kebenaran.ORDER BY
klausa Anda . Kalau tidak, Anda memiliki bug. Jika kolom seperti itu belum ada, maka Anda perlu menambahkannya. Opsi khas untuk kolom seperti ini adalah kolom cap waktu penyisipan atau kunci penambahan otomatis. Kunci peningkatan otomatis lebih dapat diandalkan.Masalah 2: Membuat memori menjadi efisien
Setelah Anda memastikan itu dijamin akan mengembalikan data dalam urutan yang Anda harapkan, Anda dapat memanfaatkan fakta ini untuk membuat jenis memori jauh lebih efisien. Cukup tambahkan kolom
row_number()
ataudense_rank()
(atau setara dengan basis data Anda) ke set hasil kueri Anda. Sekarang setiap baris memiliki indeks yang akan memberi Anda indikasi langsung tentang urutan seharusnya, dan Anda dapat mengurutkannya dalam memori dengan mudah. Pastikan Anda memberi indeks nama yang bermakna (sepertisortedBySomethingIndex
).Biola. Sekarang Anda tidak perlu lagi bergantung pada urutan hasil basis data.
Masalah 3: Apakah Anda bahkan perlu melakukan pemrosesan kode ini?
SQL sebenarnya sangat kuat. Ini adalah bahasa deklaratif luar biasa yang memungkinkan Anda melakukan banyak transformasi dan agregasi pada data Anda. Sebagian besar DB bahkan mendukung operasi lintas baris saat ini. Mereka disebut fungsi jendela atau analitik:
OVER
Klausa SQL Server untuk fungsi jendelaApakah Anda bahkan perlu menarik data Anda ke dalam memori seperti ini? Atau bisakah Anda melakukan semua pekerjaan dalam kueri SQL dengan menggunakan fungsi jendela? Jika Anda dapat melakukan semua (atau bahkan mungkin hanya bagian penting) dari pekerjaan di DB, fantastis! Masalah kode Anda hilang (atau menjadi lebih sederhana)!
Masalah 4: Anda melakukan apa untuk itu
data
?Dengan asumsi Anda tidak dapat melakukan semuanya dalam DB, biarkan saya meluruskan ini. Anda mengambil data sebagai peta (yang dikunci oleh hal-hal yang tidak ingin Anda urutkan berdasarkan), lalu Anda mengulanginya dengan urutan penyisipan , dan memodifikasi peta dengan mengganti nilai beberapa kunci dan menambahkan yang baru?
Maaf, tapi apa-apaan ini?
Penelepon seharusnya tidak perlu khawatir tentang semua ini . Sistem yang Anda buat sangat rapuh. Hanya perlu satu kesalahan bodoh (bahkan mungkin dibuat sendiri, seperti yang telah kita semua lakukan) untuk membuat satu perubahan kecil yang salah dan semuanya runtuh seperti setumpuk kartu.
Ini mungkin ide yang lebih baik:
List
.Variasi yang mungkin bisa berupa membangun representasi yang diurutkan dan kemudian membuat peta kunci untuk diindeks . Ini akan memungkinkan Anda memodifikasi salinan yang disortir di tempatnya, tanpa sengaja membuat duplikat.
Atau mungkin ini lebih masuk akal: singkirkan
data
parameternya dan buatprocessData
benar - benar mengambil datanya sendiri. Anda kemudian dapat mendokumentasikan bahwa Anda melakukan ini karena memiliki persyaratan yang sangat spesifik tentang cara pengambilan data. Dengan kata lain, buat fungsi memiliki seluruh proses, bukan hanya satu bagian saja; inter-dependensi terlalu kuat untuk membagi logika menjadi potongan yang lebih kecil. (Ubah nama fungsi dalam proses.)Mungkin ini tidak akan berhasil untuk situasi Anda. Saya tidak tahu tanpa detail lengkap masalah. Tapi saya tahu desain yang rapuh dan membingungkan ketika saya mendengarnya.
Ringkasan
Saya pikir masalah di sini pada akhirnya adalah bahwa setan ada dalam perinciannya. Ketika saya mulai mengalami masalah seperti ini, biasanya karena saya memiliki representasi data saya yang tidak sesuai untuk masalah yang saya coba selesaikan. Solusi terbaik adalah menemukan representasi yang lebih baik , dan kemudian masalah saya menjadi sederhana (mungkin tidak mudah, tetapi langsung) untuk dipecahkan.
Temukan seseorang yang mendapatkan poin itu: pekerjaan Anda adalah mengurangi masalah Anda menjadi serangkaian masalah yang sederhana dan langsung. Kemudian Anda dapat membuat kode yang kuat dan intuitif. Bicaralah pada mereka. Kode yang bagus dan desain yang bagus membuat Anda berpikir bahwa ada orang idiot yang bisa memikirkannya, karena mereka sederhana dan mudah. Mungkin ada pengembang senior yang memiliki pola pikir yang bisa Anda ajak bicara.
sumber
select key, value from table where ... order by othercolumn
, dan perlu mempertahankan pemesanan dalam pemrosesan mereka. Urutan penyisipan yang mereka maksudkan adalah urutan penyisipan ke dalam peta mereka , ditentukan oleh urutan yang digunakan dalam kueri mereka, bukan urutan penyisipan ke dalam basis data . Hal ini diperjelas oleh penggunaanLinkedHashMap
, yang merupakan struktur data yang memiliki karakteristik baik dariMap
dan dariList
pasangan kunci-nilai.order by
klausul dalam query, tetapi non-sepele ( tidak hanyaorder by column
), jadi saya ingin menghindari reimplementing penyortiran di Jawa. Meskipun SQL sangat kuat (dan kita berbicara tentang database Oracle 11g di sini), sifatprocessData
algoritme membuatnya lebih mudah untuk diekspresikan di Jawa. Dan ya, "urutan penyisipan" berarti " urutan penyisipan peta ", yaitu urutan hasil kueri.