Di sebagian besar kode Java, saya melihat orang mendeklarasikan objek Java seperti ini:
Map<String, String> hashMap = new HashMap<>();
List<String> list = new ArrayList<>();
dari pada:
HashMap<String, String> hashMap = new HashMap<>();
ArrayList<String> list = new ArrayList<>();
Mengapa ada preferensi untuk mendefinisikan objek Java menggunakan antarmuka daripada implementasi yang sebenarnya akan digunakan?
Jawaban:
Alasannya adalah bahwa implementasi antarmuka ini biasanya tidak relevan ketika menanganinya, oleh karena itu jika Anda mewajibkan pemanggil untuk meneruskan
HashMap
metode, maka Anda pada dasarnya mewajibkan implementasi yang digunakan. Jadi sebagai aturan umum, Anda seharusnya menangani antarmuka daripada implementasi yang sebenarnya dan menghindari rasa sakit dan penderitaan yang mungkin mengakibatkan harus mengubah semua tanda tangan metode menggunakanHashMap
ketika Anda memutuskan Anda harus menggunakanLinkedHashMap
sebagai gantinya.Harus dikatakan bahwa ada pengecualian untuk ini ketika implementasi relevan. Jika Anda memerlukan peta saat pesanan penting, maka Anda dapat meminta
TreeMap
atauLinkedHashMap
harus dilewati, atau lebih baik lagiSortedMap
yang tidak menentukan implementasi tertentu. Ini mewajibkan penelepon untuk selalu melewati jenis implementasi Peta tertentu dan sangat mengisyaratkan bahwa urutan itu penting. Yang mengatakan, bisakah Anda menimpaSortedMap
dan melewati yang tidak disortir? Ya, tentu saja, namun mengharapkan hal-hal buruk terjadi sebagai akibatnya.Namun praktik terbaik masih menetapkan bahwa jika tidak penting, Anda tidak boleh menggunakan implementasi spesifik. Ini berlaku secara umum. Jika Anda berurusan dengan
Dog
dan dariCat
manaAnimal
, untuk memanfaatkan warisan dengan sebaik-baiknya, Anda harus menghindari metode khusus untukDog
atauCat
. Melainkan semua metode dalamDog
atauCat
harus menimpa metode dalamAnimal
dan itu akan menghemat masalah Anda dalam jangka panjang.sumber
SortedMap
, bukanTreeMap
.SortedMap
adalah salah satu dari beberapa implementasi yang berhubungan dengan pemesanan. Selain itu intinya.TreeMap
juga memesan item sesuai dengan implementasi kunciComparable
atau diberikanComparator
antarmuka.LinkedHashMap
tidak diterapkanSortedMap
. Satu-satunya subclass dariSortedMap
adalahConcurrentSkipListMap
danTreeMap
.Dalam kata-kata Layman:
Alasan yang sama mengapa pembuat kelistrikan listrik membangun produk mereka dengan colokan listrik alih-alih hanya melepas kabel, dan rumah-rumah dilengkapi dengan soket dinding alih-alih melepas kabel yang mencuat dari dinding.
Dengan menggunakan colokan standar, mereka memungkinkan untuk memasang colokan yang sama di colokan yang kompatibel di sekitar rumah.
Dari sudut pandang stopkontak, tidak masalah apakah Anda mencolokkan TV atau stereo.
Itu membuat alat dan stopkontak lebih berguna.
Ambil contoh metode yang menerima Peta sebagai argumen.
Metode ini akan berfungsi terlepas dari Anda melewati HashMap atau LinkedHashMap, asalkan ini subclass dari Peta.
Itu prinsip substitusi Liskov .
Dalam kode sampel yang Anda berikan, itu berarti Anda nantinya dapat, untuk beberapa alasan, mengubah implementasi konkret Hash dan Anda tidak perlu mengubah sisa kode.
Masalah dengan perangkat lunak adalah bahwa, karena relatif mudah untuk mengubah hal-hal di kemudian hari tanpa membuang batu bata atau mortir, orang beranggapan bahwa pemikiran kedepan tidak sebanding dengan waktu. Tetapi kenyataan telah menunjukkan kepada kita bahwa pemeliharaan perangkat lunak sangat mahal.
sumber
Ini untuk mengikuti prinsip pemisahan antarmuka ('I' dalam SOLID ). Ini mencegah kode yang menggunakan objek-objek dari bergantung pada metode objek-objek yang tidak perlu, yang membuat kode kurang digabungkan, dan karenanya lebih mudah untuk berubah.
Misalnya, jika nanti Anda benar-benar membutuhkannya
LinkedHashMap
, Anda dapat dengan aman melakukan perubahan itu tanpa memengaruhi kode lain.Namun, ada trade off, karena Anda secara artifisial membatasi kode yang dapat mengambil objek Anda sebagai parameter. Katakanlah ada di suatu tempat fungsi yang membutuhkan sebuah
HashMap
untuk beberapa alasan. Jika Anda mengembalikanMap
, Anda tidak bisa meneruskan objek Anda ke fungsi itu. Anda harus menyeimbangkan kemungkinan suatu saat di masa depan membutuhkan fungsionalitas ekstra yang ada di kelas yang lebih konkret dengan keinginan untuk membatasi kopling dan menjaga antarmuka publik Anda sekecil mungkin.sumber
Memiliki variabel yang dibatasi ke antarmuka memastikan tidak ada penggunaan variabel yang akan menggunakan
HashMap
fungsionalitas tertentu yang mungkin tidak ada pada antarmuka, sehingga instance dapat diubah tanpa perhatian kemudian ke implementasi yang berbeda selama instance baru juga mengimplementasikan antarmuka.Untuk alasan ini, kapan pun Anda ingin menggunakan antarmuka objek, selalu merupakan praktik yang baik untuk mendeklarasikan variabel Anda sebagai antarmuka dan bukan implementasi khusus, ini berlaku untuk semua jenis objek yang dapat Anda gunakan yang memiliki antarmuka. Alasan Anda melihatnya sering adalah banyak orang telah membangun ini sebagai kebiasaan.
Yang mengatakan, itu tidak berbahaya untuk berhenti menggunakan antarmuka kadang-kadang, dan kebanyakan dari kita dengan sembrono tidak selalu mengikuti aturan ini, tanpa bahaya nyata. Ini hanya praktik yang baik untuk diikuti ketika Anda merasa kode dapat diubah dan membutuhkan pemeliharaan / pertumbuhan di masa depan. Ini kurang menjadi perhatian ketika Anda meretas kode yang tidak Anda curigai akan berumur panjang atau memiliki banyak kepentingan. Juga melanggar aturan ini biasanya memiliki konsekuensi kecil bahwa mengubah implementasi ke yang lain mungkin memerlukan sedikit refactoring, jadi jika Anda tidak selalu mengikutinya Anda tidak akan banyak menyakiti diri sendiri, meskipun tidak ada salahnya untuk mengikutinya juga .
sumber