Mengapa subkelas terlalu buruk (dan karenanya mengapa kita harus menggunakan prototipe untuk menghilangkannya)?


10

Saya membaca tentang pola desain, dan saya membaca bahwa pola desain prototipe tidak menghilangkan subclass yang berlebihan.

Mengapa subklas buruk? Apa keuntungan menggunakan prototipe jika dibandingkan dengan subklas?


kata siapa ? Anda punya tautan?
camus

Saya sedang membaca hal.118 buku ini. goo.gl/6JGw1
David Faux

Jawaban:


19

Mengapa subklas terlalu buruk

"Terlalu banyak" adalah panggilan penilaian; tetapi ambil dari saya itu buruk. Kode yang saya gunakan memiliki pewarisan DEEP dan kodenya sulit dibaca, dimengerti, diikuti, ditelusuri, didebug, dll. Secara efektif tidak mungkin untuk menulis kode uji untuk hal-hal ini.

Pola prototipe tidak jauh dengan subclassing

Atau apakah pertanyaannya berarti "tidakkah terlalu banyak subklas?". Pola ini membutuhkan kloning objek "templat" untuk menghindari subklasifikasi, setidaknya pada saat itu. Tidak ada aturan yang mengatakan bahwa "templat" tidak boleh menjadi subkelas.

Komposisi nikmat daripada warisan

Gagasan ini di sini juga mencakup delegasi dan agregasi. Mengikuti heuristik ini berarti perangkat lunak Anda cenderung lebih fleksibel, lebih mudah dirawat, diperluas, dan digunakan kembali.

Ketika kelas terdiri dari bagian-bagian Anda dapat mengganti bagian-bagian tersebut saat runtime . Ini memiliki efek mendalam pada testabilitas.

Pengujian lebih mudah . Anda dapat menggunakan bagian palsu (mis. "Mengejek", "ganda" dan ujicoba lainnya). Warisan mendalam kode kami berarti kami harus membuat seluruh hierarki untuk menguji sedikit pun. Dalam kasus kami itu tidak mungkin tanpa menjalankan kode di lingkungan nyata itu. Sebagai contoh, kita memerlukan database untuk membuat instance objek bisnis.

Perubahan datang dengan efek samping dan ketidakpastian - Semakin "dasar" kelas semakin luas efeknya, baik atau buruk. Mungkin ada perubahan yang Anda tidak berani lakukan karena efek samping yang tidak pasti. Atau perubahan yang baik untuk suatu tempat dalam rantai warisan kita adalah buruk untuk yang lain. Ini tentu saja pengalaman saya.


Saya akan sangat tertarik untuk melihat beberapa contoh ketika pewarisan membuat pengujian (terutama mengejek) sulit dan bagaimana komposisi membantu dengan itu.
Armand

@alison: Metode dalam kelas turunan yang menggunakan metode lain dari kelas dasar di mana implementasi di kelas dasar membuatnya hampir mustahil untuk menguji skenario kesalahan. Seandainya itu komposisi, akan lebih mudah untuk menyuntikkan objek yang menyebabkan kesalahan muncul
Rune FS

@ allison: Contoh? Ketika basis kode sangat besar, ketika kelas dasar digunakan oleh lusinan kelas secara langsung dan ratusan oleh warisan. Karena titik warisan mendalam digunakan kembali dan kelas dasar digeneralisasikan ke titik bahwa jejak tumpukan debugger tidak dapat menunjukkan metode apa yang sebenarnya dipanggil. Akhirnya, Ketika tidak ada injeksi ketergantungan sudah dibangun ke Frankenstein seperti itu. Kelas tingkat atas mungkin "menjadi" setengah lusin atau lebih hal-hal lain yang secara kolektif "memiliki" puluhan objek internal - masing-masing dengan rumah hiburan warisan mereka sendiri.
radarbob

8

Saya pikir salah satu alasan ini telah dianggap sebagai praktik yang buruk adalah bahwa seiring waktu setiap subclass dapat berisi atribut dan metode yang tidak masuk akal untuk objek yang semakin Anda turun rantai (dalam hierarki yang kurang berkembang). Anda bisa berakhir dengan kelas membengkak yang berisi item yang tidak masuk akal untuk kelas itu.

Saya agnostik tentang ini sendiri. Tampaknya dogmatis untuk mengatakan itu buruk. Apa pun buruk ketika disalahgunakan.


2

Dua alasan.

  1. Apakah kinerja runtime. Setiap kali Anda memanggil subkelas dari superclass, Anda melakukan pemanggilan metode, jadi jika Anda telah membuat lima kelas dan memanggil metode di kelas dasar, Anda akan melakukan lima pemanggilan metode. Sebagian besar kompiler / runtime akan mencoba mengenali hal ini dan mengoptimalkan panggilan tambahan pergi tetapi hanya aman untuk melakukan ini untuk kasus yang sangat sederhana.

  2. Apakah kewarasan sesama programmer Anda. Jika Anda bersarang lima kelas saya harus memeriksa keempat kelas induk untuk memastikan Anda benar-benar memanggil metode di kelas dasar, itu akan membosankan. Saya mungkin juga harus melangkah melalui lima metode doa ketika saya men-debug program.


6
-1: Anda benar tentang # 2; tapi bukan tentang # 1. Beberapa lapisan warisan tidak akan selalu mempengaruhi kinerja runtime.
Jim G.

Khawatir tentang beberapa panggilan prosedur tambahan pada tingkat kode mesin dan menggunakan OP dan warisan, dan Anda khawatir tentang kewarasan sesama programmer .....
mattnz

@ Jim. Mungkin tidak, tetapi bisa. :) Ada juga kemungkinan penggunaan memori yang perlu dikhawatirkan: jika Anda tidak menggunakan kembali semua variabel basis, mereka mungkin masih dialokasikan sebagai bagian dari membangun objek.
Adam Lear

2

"Terlalu banyak" adalah panggilan penilaian.

Seperti kebanyakan hal dalam pemrograman, sub-klasifikasi secara inheren tidak buruk ketika masuk akal. Ketika model solusi masalah Anda lebih masuk akal sebagai hierarki daripada komposisi bagian, subklas mungkin pilihan yang disukai.

Yang mengatakan, lebih menyukai komposisi daripada warisan adalah aturan praktis yang baik.

Ketika Anda subkelas, pengujian bisa lebih sulit (seperti yang dicatat radarbob ). Dalam hierarki yang mendalam, mengisolasi kode bermasalah lebih sulit karena instantiating subclass membutuhkan membawa seluruh hirarki superclass dan banyak kode tambahan. Dengan pendekatan komposisi, Anda dapat mengisolasi dan menguji setiap komponen objek agregat Anda dengan unit test, objek tiruan, dll.

Subkelas juga dapat menyebabkan Anda mengekspos detail implementasi yang mungkin tidak Anda inginkan. Ini membuatnya sulit untuk mengontrol akses ke representasi data Anda yang mendasarinya dan itu mengikat Anda pada implementasi tertentu dari model dukungan Anda.

Salah satu contoh yang bisa saya pikirkan adalah java.util.Properties, yang diwarisi dari Hashtable. Kelas Properties hanya dimaksudkan untuk menyimpan pasangan String-String (ini dicatat di Javadocs). Karena pewarisan, metode put dan putAll dari Hashtable telah terpapar ke pengguna Properties. Sementara cara "benar" untuk menyimpan properti adalah dengan setProperty (), sama sekali tidak ada yang mencegah pengguna untuk memanggil put () dan mengirimkan String dan Object.

Pada dasarnya, semantik Properti tidak didefinisikan dengan baik karena warisan. Selain itu, jika ada orang yang ingin mengubah objek dukungan untuk Properti, dampaknya akan memiliki dampak yang jauh lebih besar pada kode yang menggunakan Properti daripada jika Properti telah mengambil pendekatan yang lebih komposisional.


2

Warisan dapat merusak enkapsulasi dalam beberapa kasus, dan jika itu terjadi itu buruk. Baca lebih lanjut.


Di masa lalu yang baik tanpa warisan, perpustakaan akan menerbitkan API dan aplikasi yang menggunakannya memanfaatkan apa yang dapat dilihat secara publik , dan perpustakaan sekarang memiliki caranya sendiri untuk menangani roda gigi internal yang terus berubah tanpa merusak Aplikasi.

Seiring dengan perkembangan kebutuhan, perpustakaan dapat berkembang dan dapat memiliki lebih banyak pelanggan; atau dapat memberikan fungsionalitas yang diperluas dengan mewarisi dari kelasnya sendiri dengan rasa lain. Sejauh ini baik.

Namun, hal mendasarnya adalah, jika sebuah aplikasi mengambil kelas dan mulai subkelasnya, sekarang sebuah subkelas sebenarnya adalah klien daripada mitra internal. Namun, tidak seperti cara jelas yang jelas bahwa API publik didefinisikan, subclass sekarang jauh lebih dalam di dalam perpustakaan (akses ke semua variabel pribadi dan sebagainya). Ini belum buruk, tetapi karakter jahat dapat menjembatani API yang terlalu banyak di dalam APP maupun di perpustakaan-

Intinya sementara ini mungkin tidak selalu terjadi tetapi,

Sangat mudah untuk menyalahgunakan warisan untuk memecah enkapsulasi

Mengizinkan subclassing bisa salah jika saat itu.


1

Jawaban Cepat Singkat:

Tergantung pada apa yang Anda lakukan.

Jawaban Membosankan yang Diperpanjang:

Pengembang dapat membuat aplikasi. menggunakan salah satu, subclassing atau templat (prototypal). Terkadang satu teknik bekerja lebih baik. Terkadang techinque lain bekerja lebih baik.

Memilih dengan teknik berfungsi paling baik, juga membutuhkan, untuk mempertimbangkan apakah skenario "Warisan Berganda" hadir. Bahkan jika bahasa pemrograman hanya mendukung pewarisan tunggal, templat atau prototipe.

Catatan Pelengkap:

Beberapa jawaban terkait dengan "pewarisan berganda". Sebenarnya, bukan pertanyaan utama, itu terkait dengan subjek. Ada beberapa posting yang serupa tentang "pewarisan berganda vs komposisi". Saya punya kasus di mana saya mencampur keduanya.

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.