Mengapa mendefinisikan objek Java menggunakan antarmuka (misalnya Peta) daripada implementasi (HashMap)


17

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:


26

Alasannya adalah bahwa implementasi antarmuka ini biasanya tidak relevan ketika menanganinya, oleh karena itu jika Anda mewajibkan pemanggil untuk meneruskan HashMapmetode, 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 menggunakan HashMapketika Anda memutuskan Anda harus menggunakan LinkedHashMapsebagai gantinya.

Harus dikatakan bahwa ada pengecualian untuk ini ketika implementasi relevan. Jika Anda memerlukan peta saat pesanan penting, maka Anda dapat meminta TreeMapatau LinkedHashMapharus dilewati, atau lebih baik lagi SortedMapyang 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 menimpa SortedMapdan 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 Dogdan dari Catmana Animal, untuk memanfaatkan warisan dengan sebaik-baiknya, Anda harus menghindari metode khusus untuk Dogatau Cat. Melainkan semua metode dalam Dogatau Catharus menimpa metode dalam Animaldan itu akan menghemat masalah Anda dalam jangka panjang.


Saat Anda membutuhkan peta yang diurutkan, tipe parameter seharusnya SortedMap, bukan TreeMap.
Cephalopod

@Arian SortedMapadalah salah satu dari beberapa implementasi yang berhubungan dengan pemesanan. Selain itu intinya. TreeMapjuga memesan item sesuai dengan implementasi kunci Comparableatau diberikan Comparatorantarmuka.
Neil

Tidak, SortedMap bukan implementasi, itulah intinya. Ini adalah antarmuka untuk peta yang mengurutkan berdasarkan kunci.
Cephalopod

1
@Arian Ah, saya mengerti maksud Anda. Benar, SortedMap yang lebih baik karena itu tidak memaksa implementasi. Saya akan melakukan penyesuaian yang tepat.
Neil

Sebenarnya, LinkedHashMaptidak diterapkan SortedMap. Satu-satunya subclass dari SortedMapadalah ConcurrentSkipListMapdan TreeMap.
bcorso

10

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.


4

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 HashMapuntuk beberapa alasan. Jika Anda mengembalikan Map, 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.


3

Memiliki variabel yang dibatasi ke antarmuka memastikan tidak ada penggunaan variabel yang akan menggunakan HashMapfungsionalitas 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 .

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.