Penggantian misalnya Java?

10

Jadi saya cukup baru dalam pemrograman di dunia nyata (di luar proyek akademik) dan telah menemukan banyak posting yang mengatakan bahwa menggunakan instanceofadalah hal yang buruk untuk digunakan untuk menentukan kelas apa objek tertentu.

Situasi saya adalah saya memiliki tiga kelas, kelas produk dasar, satu yang memanjang dari itu dan yang lain memanjang dari itu. Ini semua disimpan dalam tabel yang sama dalam database dan saya memiliki beberapa kode yang perlu menggunakan metode pada masing-masing untuk menarik data dari mereka.

Apa praktik terbaik untuk menyiasati cara melakukannya? Saya telah membaca beberapa hal tentang polimorfisme tetapi saya tidak dapat menemukan contoh yang memperbaiki masalah yang saya miliki. Mereka semua biasanya menimpa metode yang bagi saya tidak akan berfungsi karena saya harus menarik hal-hal yang berbeda dari objek yang berbeda.

Apakah ada cara yang lebih baik untuk melakukan ini atau saya terjebak dengan menggunakan instanceofatau semacam refleksi untuk mendapatkan bidang khusus untuk objek?

Thomas Mitchell
sumber
10
Bukan karena kata kunci instanceofsalah; mencoba menemukan kelas suatu objek biasanya merupakan masalah. Tidak selalu salah, tetapi mungkin dalam kasus Anda itu. Mungkin jika Anda memberi tahu kami apa yang ingin Anda capai, kami dapat menyarankan solusi menggunakan polimorfisme.
Andres F.
2
Oke, setiap kelas memiliki data khusus untuk itu. Saya ingin menarik data spesifik dari ini. Saya pikir saya telah menyadari jawabannya dengan bantuan yang saya miliki. Sesuatu seperti metode yang disebut getSpecifics()yang diimplementasikan secara berbeda pada masing-masing, dengan masing-masing mengembalikan data spesifik ke kelas?
Thomas Mitchell

Jawaban:

16

Alasannya instanceofadalah berkecil hati adalah bahwa itu bukan OOP.

Seharusnya tidak ada alasan bagi penelepon / pengguna suatu objek untuk mengetahui kelas konkret mana yang merupakan turunan dari tipe variabel yang dinyatakannya.

Jika Anda memerlukan perilaku berbeda dalam subkelas, tambahkan metode dan implementasikan secara berbeda.

aneh ratchet
sumber
1
Jadi metode getSpecifics()(atau yang serupa) pada setiap kelas yang akan mengembalikan spesifik untuk setiap kelas. Apakah ini pendekatan terbaik?
Thomas Mitchell
@Schmooo Anda benar-benar perlu memikirkan di mana fungsi umum ada di dalam pohon kelas dan kontrak apa yang ada di setiap tingkat.
3
Tetapi bagaimana dengan kasus ketika objek Anda melintas dan informasi jenisnya hilang? Contoh saya membuat a List. Saya meneruskannya ke objek yang mengambil Iterable. Sekarang objek kedua meneruskannya ke objek ketiga yang mengambil salah satu Listuntuk optimasi, atau Iterabletetapi jauh lebih lambat. Yang kedua seharusnya tidak tahu bahwa itu daftar, tetapi yang ketiga sangat ingin tahu. Bukankah objek ketiga harus memeriksa instanceof untuk melihat apakah ia dapat menerapkan optimasi? Lihat misalnya jambu biji FluentIterableyang melakukan hal itu.
Laurent Bourgault-Roy
1
Saya akan mengatakan bahwa tidak selalu halnya Anda harus menambahkan metode ke kelas. Sebagai contoh, beberapa kode mendapat pengecualian dan seharusnya melakukan sesuatu dengannya tergantung pada jenisnya. Katakan, buat laporan atau lakukan sesuatu untuk memulihkan dari kesalahan. Fungsionalitas semacam ini jelas tidak sesuai dengan pengecualian. Atau, jika kelas-kelas tersebut berasal dari beberapa perpustakaan eksternal, maka Anda bahkan tidak memiliki sarana untuk memodifikasi kelas-kelas ini. Dalam hal ini saya pikir itu benar - benar sah untuk mengandalkan instanceof.
Malcolm
9

instanceof tidak selalu merupakan hal yang buruk, namun itu adalah sesuatu yang harus dilihat.

Contoh di mana ia bekerja dengan benar adalah di tempat di mana seseorang mendapatkan koleksi tipe dasar dan Anda hanya ingin yang subtipe. Mendapatkan alamat jaringan dari NetworkInterface.getNetworkInterfaces()mengembalikan kembali objek NetworkInterface yang memiliki koleksi objek InetAddress, beberapa di antaranya adalah Inet4Address dan beberapa di antaranya adalah Inet6Address. Jika seseorang ingin memfilter koleksi untuk objek Inet4Address, perlu menggunakan instanceof.

Dalam situasi yang dijelaskan di posting asli, ada kelas Base, sesuatu yang memperluas kelas dasar itu dan sesuatu yang memperluas kelas diperluas. Meskipun tidak sepenuhnya informatif, ini tampaknya memiliki dasar dari beberapa desain yang kurang ideal.

Ketika Anda mengembalikan kelas dasar kecuali ada alasan yang baik untuk itu dirancang seperti itu (kompatibilitas mundur antara spesifikasi versi sebelumnya) Anda tidak harus mencoba mengintip jenis yang mendasarinya. Jika Anda mengembalikan Set, Anda tahu Anda mendapatkan set. Ini memungkinkan pengembang untuk kemudian mengubah pikirannya untuk mengembalikan tipe yang lebih spesifik (SortedSet) atau mengubah tipe yang mendasarinya (HashSet ke TreeSet) tanpa merusak apa pun.

Pertimbangkan kembali desain Anda tentang bagaimana objek terstruktur dan diasuh untuk melihat apakah seseorang dapat membuat model kelas yang lebih baik yang tidak memerlukan perbedaan jenis.


sumber
Ada kemungkinan bahwa memiliki antarmuka menentukan isOfType(SomeEnum.IPv4)metode bisa menjadi cara yang lebih baik untuk menyaring kualitas seperti itu daripada memeriksa jenis beton melalui instanceof. Bagaimana jika Anda ingin membagi kelas implementasi IPv4 Anda nanti? Bukannya ini selalu lebih baik, tapi itu pertimbangan.
Steven Schlansker
@StevenSchlansker Itu bisa bekerja untuk kelas tertentu. Tetapi bagaimana jika seseorang perlu memeriksa jenis beton untuk melihat apakah gips mungkin (atau akankah satu gips dan menangkap pengecualian?) Inet6Address mengimplementasikan lebih banyak metode daripada InetAddress. Akan sulit baginya untuk bekerja dengan antarmuka (enum yang menyebutkan setiap kelas dalam paket? Atau kelas loader?) Dan itu berarti metode tersebut perlu diimplementasikan dengan tangan (atau beberapa kode refleksi dalam Objek). Pertimbangkan cara melakukannya (o instanceof Serializable) || (o instanceof Externalizable). instanceof lebih baik daripada alternatif
1

Anda dapat menggunakan metode getClass ().

Apakah Anda yakin perlu tiga kelas berbeda? Mungkin satu kelas dengan saklar di dalam akan melayani lebih baik?

Gangnus
sumber
7
getClassdan instanceofberbagi kerugian. Polimorfisme lebih baik daripada keduanya ketika cocok, dan saya tidak melihatnya tidak cocok dengan kasus penggunaan OP.
Saya tidak menentang kalimat pertama Anda. Tapi yang kedua - maaf, saya tidak mengerti apa yang Anda maksudkan sama sekali.
Gangnus
1
Dengan getClassapakah saya masih berbagi masalah yang sama dengan menggunakan instanceof? Saya masih harus mencari tahu yang saya miliki dan kemudian memanggil satu set fungsi. Idealnya saya ingin metode yang mengembalikan data spesifik ke kelas itu tanpa perlu dilemparkan ke objek itu.
Thomas Mitchell
Saya mengeluh tentang Anda mengabaikan Polimorfisme, karena ini seringkali merupakan pilihan yang lebih baik. Saya cukup yakin kasus penggunaan dalam pertanyaan dapat dilakukan dengan polimorfisme, jadi saya tidak melihat perlunya menggunakan keduanya. (Selain itu, hanya mereproduksi jawaban orang lain tidak baik.)
2
@ Gangus Saya tidak menganggap ini sebagai "serangan", maksud saya jangan tersinggung. Tapi apa pun. Tidak, pertanyaannya bukan "apa lagi yang bisa digunakan", itu "adakah cara yang lebih baik untuk melakukan ini". Kecuali jika Anda ingin berdebat getClassadalah cara yang lebih baik untuk melakukannya, itu tidak ada urusan mengambil sebagian besar jawaban ;-)
1

Biasanya ketika saya menemukan diri saya ingin tahu jenis sesuatu itu berarti saya menerapkan struktur objek yang salah. Sebagian besar kali ini karena melanggar LSP .

Namun ada saat di mana saya berharap saya memiliki cara untuk melakukan pengiriman dinamis dan menghemat satu ton kode pelat ketel dan memperbaiki struktur objek saya. C # memberikan kata kunci dinamis dalam angsuran kerangka kerja yang lebih baru tetapi sejauh yang saya tahu Java masih tidak memiliki sesuatu yang serupa.

Yang mengatakan, instanceof umumnya lebih baik daripada membandingkan kelas karena akan mendukung warisan dengan benar. Anda juga dapat menggunakan metode seperti issignableFrom dan lainnya dari API refleksi. Jika Anda ingin mengimplementasikan sesuatu seperti pengiriman dinamis, itu bisa dilakukan melalui API refleksi tetapi waspadalah, itu akan lambat. Gunakan dengan hati-hati, idealnya Anda harus memperbaiki struktur objek dan desing aplikasi Anda jika Anda bisa.

Semoga ini membantu

Newtopian
sumber