JavaRush /Java Blog /Random-ID /Warisan sebagai sebuah fenomena
articles
Level 15

Warisan sebagai sebuah fenomena

Dipublikasikan di grup Random-ID
Sejujurnya, saya awalnya tidak merencanakan artikel ini. Saya menganggap persoalan yang ingin saya bahas di sini sepele, bahkan tidak layak untuk disebutkan. Namun dalam proses penulisan artikel untuk situs ini, saya mengangkat pembahasan tentang pewarisan ganda di salah satu forum. Akibatnya, sebagian besar pengembang ternyata memiliki pemahaman yang sangat kabur tentang warisan. Dan karenanya, dia membuat banyak kesalahan. Karena pewarisan adalah salah satu fitur terpenting OOP (jika bukan yang paling penting!), Saya memutuskan untuk membuat artikel terpisah untuk fenomena ini. * * * Pertama, saya ingin membedakan dua konsep - objek dan kelas. Konsep-konsep ini selalu membingungkan. Sementara itu, mereka adalah inti dari OOP. Dan menurut saya, perlu diketahui perbedaan keduanya. Jadi, objeknya. Pada dasarnya, itu adalah segalanya. Ini kubusnya. Kayu, biru. Panjang rusuknya 5 cm, ini adalah sebuah benda. Dan ada piramida. Plastik, merah. rusuk 10 cm. Ini juga sebuah objek. Apa kesamaan mereka? Ukuran berbeda. Bentuk berbeda. Bahan yang berbeda. Namun, mereka memiliki kesamaan. Pertama-tama, kubus dan piramida adalah polihedra beraturan. Itu. jumlah jumlah titik dan jumlah sisi lebih banyak 2 dari jumlah sisi. Lebih jauh. Kedua bentuk tersebut memiliki wajah, tepi, dan simpul. Kedua sosok tersebut memiliki ciri khas seperti ukuran tulang rusuk. Kedua bentuk tersebut dapat diputar. Kedua gambar tersebut dapat digambar. Dua properti terakhir sudah menjadi perilaku. Dan seterusnya. Praktek pemrograman menunjukkan bahwa mengoperasikan objek homogen jauh lebih mudah dibandingkan dengan objek heterogen. Dan karena masih ada kesamaan di antara tokoh-tokoh ini, ada keinginan untuk menyoroti kesamaan ini. Di sinilah konsep kelas berperan. Jadi, definisinya.
Kelas adalah deskripsi properti umum dari sekelompok objek. Properti ini dapat berupa karakteristik objek (ukuran, berat, warna, dll), dan perilaku, peran, dll.
Komentar. Kata “semua” (deskripsi semua properti) tidak diucapkan. Artinya, suatu objek dapat dimiliki oleh beberapa kelas berbeda. Warisan sebagai sebuah fenomena - 1 Mari kita ambil contoh yang sama dengan bentuk geometris sebagai dasarnya. Gambaran paling umum adalah polihedron beraturan . Terlepas dari ukuran tepi, jumlah wajah dan simpul. Satu-satunya hal yang kita ketahui adalah bahwa gambar ini memiliki simpul, sisi, dan sisi, dan panjang sisinya sama. Lebih jauh. Kita bisa membuat deskripsinya lebih spesifik. Katakanlah kita ingin menggambar polihedron ini . Mari kita perkenalkan konsep seperti polihedron beraturan yang digambar . Apa yang kita butuhkan untuk menggambar? Deskripsi metode penggambaran umum yang tidak bergantung pada koordinat titik tertentu. Mungkin warna objeknya. Sekarang mari kita perkenalkan kelas Cube dan Tetrahedron . Objek yang termasuk dalam kelas ini tentu saja merupakan polihedra beraturan. Satu-satunya perbedaan adalah bahwa jumlah simpul, tepi, dan permukaan sudah ditetapkan secara ketat untuk setiap kelas baru. Selanjutnya, dengan mengetahui jenis gambar tertentu, kita dapat memberikan gambaran tentang cara menggambarnya. Artinya, objek apa pun dari kelas Kubus atau Tetrahedron juga merupakan objek dari kelas polihedron beraturan yang digambar . Ada hierarki kelas. Dalam hierarki ini kita turun dari gambaran yang paling umum ke yang paling spesifik. Perhatikan bahwa objek dari kelas mana pun juga cocok dengan deskripsi kelas yang lebih umum dalam hierarki. Hubungan kelas ini disebut pewarisan . Setiap kelas anak mewarisi semua properti induknya, yang lebih umum, dan (mungkin) menambahkan beberapa propertinya sendiri ke properti ini. Atau itu menimpa beberapa properti kelas induk. Berikut saya ingin mengutip dari buku klasik Gradi Bucha tentang desain berorientasi objek:
Oleh karena itu, pewarisan mendefinisikan hierarki "adalah" di antara kelas-kelas, di mana subkelas mewarisi dari satu atau lebih superkelas. Ini sebenarnya adalah ujian lakmus untuk pewarisan. Mengingat kelas A dan B, jika A "bukan" jenis B, maka A tidak boleh menjadi subkelas dari B.
Diterjemahkan kedengarannya seperti ini:
Warisan dengan demikian mendefinisikan hierarki "adalah" antar kelas, di mana subkelas mewarisi dari satu atau lebih superkelas. Faktanya, ini adalah ujian yang menentukan (secara harfiah, ujian lakmus, catatan saya) untuk warisan. Jika kita mempunyai kelas A dan B, dan jika kelas A "bukan" merupakan varian dari kelas B, maka A tidak boleh merupakan subkelas dari B.
Mereka yang telah membaca sejauh ini mungkin akan memutar-mutar jari mereka di pelipis dengan bingung. Pikiran pertama adalah ini sepele! Ini benar. Tetapi jika Anda tahu berapa banyak hierarki warisan gila yang pernah saya lihat! Dalam diskusi yang saya sebutkan di awal, salah satu peserta secara serius mewarisi tank dari... senapan mesin!!! Untuk alasan sederhana bahwa tank tersebut MEMILIKI senapan mesin. Dan ini adalah kesalahan paling umum. Warisan dikacaukan dengan agregasi - dimasukkannya satu objek ke dalam objek lain. Tank itu bukan senapan mesin, melainkan berisi senapan mesin. Dan karena kesalahan ini, paling sering ada keinginan untuk menggunakan warisan berganda. Sekarang mari kita langsung beralih ke Java. Apa yang ada dalam hal warisan? Ada dua jenis kelas dalam bahasa ini - kelas yang mampu memuat implementasi, dan kelas yang tidak mampu memuat implementasi. Yang terakhir disebut antarmuka, meskipun pada dasarnya mereka adalah kelas yang sepenuhnya abstrak. Warisan sebagai sebuah fenomena - 2 Jadi, bahasa tersebut memungkinkan Anda untuk mewarisi kelas dari kelas lain yang berpotensi berisi implementasi. TAPI HANYA DARI SATU! Izinkan saya menjelaskan mengapa hal ini dilakukan. Intinya adalah bahwa setiap implementasi hanya dapat menangani bagiannya sendiri - dengan variabel dan metode yang diketahuinya. Dan bahkan jika kita mewarisi kelas C dari A dan B , maka metode processA , yang diwarisi dari kelas A, hanya dapat bekerja dengan variabel internal a , karena ia tidak mengetahui apa pun tentang b , sama seperti ia tidak mengetahui apa pun tentang c dan metode processC . Begitu juga dengan metode processB hanya dapat bekerja dengan variabel b. Artinya, pada hakikatnya bagian-bagian yang diwariskan itu terisolasi. Kelas C pasti bisa bekerja dengan mereka, tapi juga bisa bekerja dengan bagian-bagian ini jika mereka dimasukkan sebagai bagian darinya dan bukan diwariskan. Namun, ada gangguan lain di sini, yaitu tumpang tindih nama. Jika metode processA dan processB diberi nama yang sama, katakanlah proses, lalu apa pengaruh pemanggilan metode proses kelas C ? Manakah dari dua metode yang akan dipanggil? Tentu saja, C++ memiliki kontrol dalam situasi ini, tapi ini tidak menambah keharmonisan bahasa. Jadi implementasi pewarisan tidak memberikan kelebihan, namun ada kekurangannya. Oleh karena itu, pewarisan implementasi di Java ini telah ditinggalkan. Namun, pengembang dibiarkan dengan opsi pewarisan berganda seperti warisan dari antarmuka. Dalam istilah Java, implementasi antarmuka. Apa antarmukanya? Seperangkat metode. (Saat ini kami tidak mempertimbangkan definisi konstanta dalam antarmuka; lebih lanjut tentang itu di sini .) Apa yang dimaksud dengan metode? Dan suatu metode, pada intinya, menentukan perilaku suatu objek. Bukan kebetulan bahwa nama hampir setiap metode berisi tindakan - getXXX , drawXXX , countXXX , dll. Dan karena antarmuka adalah kumpulan metode, maka antarmuka sebenarnya merupakan penentu perilaku . Pilihan lain untuk menggunakan antarmuka adalah dengan mendefinisikan peran suatu objek. Pengamat, Pendengar , dll. Dalam hal ini, metode sebenarnya merupakan perwujudan reaksi terhadap suatu peristiwa eksternal. Sekali lagi, itu adalah perilaku. Suatu objek tentu saja dapat memiliki beberapa perilaku berbeda. Jika perlu dirender, maka dirender. Jika dia perlu diselamatkan, dia diselamatkan. Yah, dll. Oleh karena itu, kemampuan untuk mewarisi dari kelas yang mendefinisikan perilaku sangatlah berguna. Demikian pula, suatu objek dapat memiliki beberapa peran berbeda. Namun implementasinyaperilakunya sepenuhnya berdasarkan hati nurani kelas anak. Warisan dari sebuah antarmuka (implementasinya) mengatakan bahwa objek kelas ini harus mampu melakukan ini dan itu. Dan BAGAIMANA melakukan hal ini ditentukan secara independen oleh masing-masing kelas yang mengimplementasikan antarmuka. Mari kita kembali ke kesalahan dalam pewarisan. Pengalaman saya dalam mengembangkan berbagai sistem menunjukkan bahwa dengan memiliki warisan dari antarmuka, Anda dapat mengimplementasikan sistem apa pun tanpa menggunakan banyak warisan implementasi. Oleh karena itu, ketika saya menemukan keluhan tentang kurangnya pewarisan berganda dalam bentuk yang ada di C++, bagi saya ini adalah tanda pasti dari desain yang salah. Kesalahan paling umum yang dilakukan adalah kesalahan yang telah saya sebutkan - warisan dikacaukan dengan agregasi. Terkadang hal ini terjadi karena asumsi yang salah. Itu. Ambil contoh speedometer, dikatakan bahwa kecepatan hanya dapat diukur dengan mengukur jarak dan waktu, setelah itu speedometer berhasil diwarisi dari penggaris dan jam, sehingga menjadi penggaris dan jam, sesuai dengan definisinya. warisan. (Permintaan saya mengukur waktu dengan speedometer biasanya dijawab dengan bercanda. Atau tidak dijawab sama sekali.) Apa kesalahannya disini? Di dalam premis. Faktanya speedometer tidak mengukur waktu. Dan jaraknya juga. Odometer, yang ditemukan di speedometer mana pun, adalah contoh klasik perangkat kedua di rumah yang sama, yaitu. pengumpulan. Tidak perlu mengukur kecepatan. Itu dapat dihapus sepenuhnya - ini tidak akan mempengaruhi pengukuran kecepatan dengan cara apa pun. Terkadang kesalahan seperti itu dilakukan dengan sengaja. Ini jauh lebih buruk. “Ya, saya tahu itu salah, tapi itu lebih nyaman bagi saya.” Hal ini dapat menyebabkan apa? Tapi inilah yang terjadi: kita akan mewarisi tank dari meriam dan senapan mesin. Lebih nyaman begini. Alhasil, tank tersebut menjadi meriam dan senapan mesin. Selanjutnya kita akan melengkapi pesawat dengan dua senapan mesin dan sebuah meriam. Apa yang kita dapatkan? Sebuah pesawat dengan senjata gantung berupa tiga tank! Karena PASTI ada orang yang tanpa sadar menggunakan tank sebagai senapan mesin. Secara eksklusif menurut hierarki warisan. Dan dia benar sekali, karena orang yang merancang hierarki seperti itu melakukan kesalahan.
Secara umum, saya tidak begitu memahami pendekatan “ lebih nyaman bagi saya seperti ini”. Sangat mudah untuk menulis seperti pendengar, dan mereka yang mengatakan tata bahasa dasar adalah kazly. Saya melebih-lebihkan, tentu saja, tetapi gagasan utamanya tetap sama - selain kenyamanan sesaat, ada yang namanya literasi. Konsep ini didefinisikan berdasarkan pengalaman banyak orang. Sebenarnya, inilah yang dalam bahasa Inggris disebut “best practice” - solusi terbaik. Dan seringkali, solusi yang terlihat lebih sederhana justru membawa banyak masalah di masa depan.
Tentu saja contoh ini terlalu berlebihan dan tidak masuk akal. Namun, ada kasus-kasus yang kurang jelas namun menimbulkan konsekuensi yang sangat buruk. Dengan mewarisi suatu objek, bukan menggabungkannya, pengembang memberi siapa pun kemampuan untuk menggunakan fungsionalitas objek induk secara langsung. Dengan segala implikasinya. Bayangkan Anda memiliki kelas yang bekerja dengan database, DBManager . Anda membuat kelas lain yang akan bekerja dengan data Anda menggunakan DBManager - DataManager . Kelas ini akan melakukan kontrol data, transformasi, tindakan tambahan, dll. Secara umum merupakan lapisan antara lapisan bisnis dan lapisan dasar. Jika Anda mewarisi DataManager dari DBManager, siapa pun yang menggunakannya akan memiliki akses ke database secara langsung. Dan, oleh karena itu, dia akan dapat melakukan tindakan apa pun yang melewati kendali, transformasi, dll. Oke, mari kita asumsikan bahwa tidak ada orang yang ingin menyebabkan kerugian yang disengaja dan tindakan langsung akan kompeten. Tetapi! Mari kita asumsikan bahwa basisnya telah berubah. Maksud saya, beberapa prinsip pengendalian atau transformasi telah berubah. Manajer Data telah diubah. Namun kode yang sebelumnya bekerja langsung dengan database akan terus bekerja. Kemungkinan besar mereka tidak akan mengingatnya. Hasilnya adalah kesalahan kelas sedemikian rupa sehingga orang yang mencarinya akan berubah menjadi abu-abu. Tidak akan pernah terpikir oleh siapa pun bahwa mereka bekerja dengan database melewati DataManager. Omong-omong, contoh dari kehidupan nyata. Butuh waktu SANGAT lama untuk menemukan kesalahannya. Akhirnya, saya akan mengatakannya lagi. Warisan HANYA digunakan ketika ada hubungan "adalah". Karena inilah inti dari pewarisan - kemampuan untuk menggunakan objek kelas anak sebagai objek kelas dasar. Jika tidak ada hubungan “is” antar kelas, TIDAK HARUS ada warisan!!! Tidak pernah dan dalam keadaan apa pun. Dan terlebih lagi – hanya karena sangat nyaman. Tautan ke sumber asli: http://www.skipy.ru/philosophy/inheritance.html
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION