Ketika Anda menggunakan konsep polimorfisme Anda membuat hierarki kelas dan menggunakan referensi orang tua Anda memanggil fungsi antarmuka tanpa mengetahui tipe spesifik yang memiliki objek. Ini bagus. Contoh:
Anda memiliki koleksi hewan dan Anda memanggil semua fungsi hewan eat
dan Anda tidak peduli apakah itu makan anjing atau kucing. Tetapi dalam hierarki kelas yang sama Anda memiliki hewan yang memiliki tambahan - selain diwariskan dan diimplementasikan dari kelas Animal
, misalnya makeEggs
, getBackFromTheFreezedState
dan sebagainya. Jadi, dalam beberapa kasus dalam fungsi Anda, Anda mungkin ingin tahu tipe spesifik untuk memanggil perilaku tambahan.
Misalnya, kalau-kalau itu adalah pagi hari dan jika itu hanya binatang maka Anda menelepon eat
, jika tidak, itu adalah manusia, maka panggil dulu washHands
, getDressed
dan baru kemudian panggil eat
. Bagaimana cara menangani kasus ini? Polimorfisme mati. Anda perlu mengetahui jenis objek, yang terdengar seperti bau kode. Apakah ada pendekatan umum untuk menangani kasus ini?
Eater
antarmuka denganeat()
metode, maka sebagai klien, Anda tidak peduli bahwaHuman
pelaksana harus menelepon terlebih dahuluwashHands()
dangetDressed()
, ini merupakan detail implementasi dari kelas ini. Jika, sebagai klien, Anda peduli akan fakta ini, kemungkinan besar Anda tidak menggunakan alat yang tepat untuk pekerjaan itu.getDressed
sebelum merekaeat
, itu tidak terjadi untuk makan siang. Tergantung pada keadaan Anda,washHands();if !dressed then getDressed();[code to actually eat]
mungkin cara terbaik untuk menerapkan ini untuk manusia. Kemungkinan lain adalah bagaimana jika hal-hal lain mengharuskan ituwashHands
dan / ataugetDressed
dipanggil? Misalkan Anda memilikileaveForWork
? Anda mungkin perlu menyusun alur program Anda untuk memilikinya sehingga itu disebut jauh sebelum itu.Jawaban:
Tergantung. Sayangnya tidak ada solusi generik. Pikirkan persyaratan Anda dan coba cari tahu apa yang harus dilakukan hal-hal ini.
Misalnya, Anda mengatakan di pagi hari hewan yang berbeda melakukan hal yang berbeda. Bagaimana Anda memperkenalkan metode
getUp()
atauprepareForDay()
atau sesuatu seperti itu. Kemudian Anda dapat melanjutkan dengan polimorfisme dan membiarkan setiap hewan melakukan rutinitas paginya.Jika Anda ingin membedakan antara hewan, maka Anda tidak harus menyimpannya tanpa pandang bulu dalam daftar.
Jika tidak ada yang berhasil, maka Anda dapat mencoba Pola Pengunjung , yang merupakan jenis peretasan untuk memungkinkan pengiriman jenis dinamis di mana Anda dapat mengirimkan pengunjung yang akan menerima panggilan balik tipe-tepat dari hewan. Namun saya akan menekankan bahwa ini harus menjadi pilihan terakhir jika semuanya gagal.
sumber
Ini adalah pertanyaan yang bagus dan ini adalah masalah yang banyak orang lakukan ketika mencoba memahami cara menggunakan OO. Saya pikir sebagian besar pengembang berjuang dengan ini. Saya berharap saya bisa mengatakan bahwa sebagian besar bisa melewatinya tetapi saya tidak yakin itu masalahnya. Sebagian besar pengembang, dalam pengalaman saya, akhirnya menggunakan tas properti pseudo-OO .
Pertama, izinkan saya menjelaskan. Ini bukan salahmu. Cara OO biasanya diajarkan sangat cacat. The
Animal
contoh adalah pelaku utama, IMO. Pada dasarnya, kita katakan, mari kita bicara tentang objek, apa yang bisa mereka lakukan. SebuahAnimal
kalengeat()
dan bisaspeak()
. Super. Sekarang buat beberapa hewan dan kode cara mereka makan dan berbicara. Sekarang Anda tahu OO, kan?Masalahnya adalah bahwa ini datang pada OO dari arah yang salah. Mengapa ada hewan dalam program ini dan mengapa mereka perlu berbicara dan makan?
Saya mengalami kesulitan memikirkan penggunaan nyata untuk suatu
Animal
tipe. Saya yakin itu ada tetapi mari kita bahas sesuatu yang menurut saya lebih mudah untuk dipikirkan: simulasi lalu lintas. Asumsikan kita ingin memodelkan lalu lintas dalam berbagai skenario. Berikut adalah beberapa hal mendasar yang harus kita lakukan untuk dapat melakukannya.Kita bisa masuk lebih dalam dengan segala macam hal pejalan kaki dan kereta api, tetapi kita akan membuatnya tetap sederhana.
Mari kita pertimbangkan
Vehicle
. Kemampuan apa yang dibutuhkan kendaraan? Perlu melakukan perjalanan di jalan. Itu harus bisa berhenti pada sinyal. Itu harus dapat menavigasi persimpangan.Ini mungkin terlalu sederhana tapi ini awal. Sekarang. Bagaimana dengan semua hal lain yang mungkin dilakukan kendaraan? Mereka bisa mematikan jalan dan menjadi parit. Apakah itu bagian dari simulasi? Tidak. Tidak perlu itu. Beberapa mobil dan bus memiliki hidrolika yang memungkinkannya untuk memantul atau berlutut. Apakah itu bagian dari simulasi? Tidak. Tidak perlu itu. Sebagian besar mobil membakar bensin. Beberapa tidak. Apakah pembangkit listrik bagian dari simulasi? Tidak. Tidak perlu itu. Ukuran ban? Tidak butuh itu Navigasi GPS? Sistem infotainment? Tidak butuh mereka.
Anda hanya perlu mendefinisikan perilaku yang akan Anda gunakan. Untuk itu, saya pikir seringkali lebih baik untuk membangun antarmuka OO dari kode yang berinteraksi dengannya. Anda mulai dengan antarmuka kosong dan kemudian mulai menulis kode yang memanggil metode tidak ada. Itulah cara Anda mengetahui metode apa yang Anda butuhkan di antarmuka Anda. Kemudian setelah Anda selesai melakukannya, Anda pergi dan mulai mendefinisikan kelas yang menerapkan perilaku ini. Perilaku yang tidak digunakan tidak relevan dan tidak perlu didefinisikan.
Inti dari OO adalah bahwa Anda dapat menambahkan implementasi baru dari antarmuka ini nanti tanpa mengubah kode panggilan. Satu-satunya cara yang berfungsi adalah jika kebutuhan kode panggilan menentukan apa yang terjadi di antarmuka. Tidak ada cara untuk mendefinisikan semua perilaku dari semua hal yang mungkin yang bisa dipikirkan nanti.
sumber
TL; DR:
Pikirkan abstraksi dan metode yang berlaku untuk semua subclass dan mencakup semua yang Anda butuhkan.
Pertama-tama mari kita tetap dengan
eat()
teladan Anda .Merupakan sifat menjadi manusia yang, sebagai prasyarat untuk makan, manusia ingin mencuci tangan dan berpakaian sebelum makan. Jika Anda ingin seseorang datang kepada Anda untuk sarapan bersama Anda, Anda tidak menyuruh mereka mencuci tangan dan berpakaian, mereka melakukannya sendiri ketika Anda mengundang mereka, atau mereka menjawab "Tidak, saya tidak bisa datang selesai, saya belum mencuci tangan, dan saya belum berpakaian ".
Kembali ke perangkat lunak:
Sebagai
Human
contoh tidak akan makan tanpa prasyarat, saya akan memilikiHuman
'seat()
metode lakukanwashHands()
dangetDressed()
jika itu belum dilakukan. Seharusnya bukan tugas Anda sebagaieat()
penelepon untuk mengetahui kekhasan itu. Alternatif manusia keras kepala adalah dengan melemparkan pengecualian ("Saya tidak siap makan!") Jika prasyarat tidak terpenuhi, membuat Anda frustrasi, tetapi setidaknya memberi tahu bahwa makan tidak berhasil.Bagaimana dengan
makeEggs()
?Saya akan merekomendasikan untuk mengubah cara berpikir Anda. Anda mungkin ingin melaksanakan tugas pagi yang dijadwalkan semua makhluk. Sekali lagi, sebagai penelepon, bukan tugas Anda untuk mengetahui apa tugas mereka. Jadi saya akan merekomendasikan
doMorningDuties()
metode yang diterapkan semua kelas.sumber
Jawabannya cukup sederhana.
Anda tidak perlu menanganinya karena tidak ada gunanya. Antarmuka biasanya dirancang tergantung pada bagaimana itu akan digunakan. Jika antarmuka Anda tidak mendefinisikan mencuci tangan, maka Anda tidak peduli sebagai penelepon antarmuka; jika Anda melakukannya Anda akan mendesainnya secara berbeda.
Misalnya, dalam pseudocode:
Sekarang Anda menerapkan
IMorningPerformer
untukAnimal
hanya melakukan makan, dan untukHuman
Anda juga menerapkannya untuk mencuci tangan dan berpakaian. Penelepon metode MorningTime Anda tidak terlalu peduli apakah itu manusia atau binatang. Yang diinginkannya adalah rutinitas pagi yang dilakukan, yang setiap objek lakukan dengan sangat baik berkat OO.Atau apakah itu?
Mengapa menganggap itu? Saya pikir ini bisa menjadi asumsi yang salah.
Ya, biasanya diselesaikan dengan hierarki kelas atau antarmuka yang dirancang dengan cermat. Perhatikan bahwa dalam contoh di atas tidak ada yang bertentangan dengan contoh Anda seperti yang Anda berikan, namun, Anda mungkin akan merasa tidak puas, karena Anda telah membuat beberapa asumsi lagi bahwa Anda tidak menulis dalam pertanyaan pada saat penulisan , dan asumsi ini mungkin dilanggar.
Dimungkinkan untuk pergi ke lubang kelinci dengan Anda memperketat asumsi Anda dan saya memodifikasi jawaban untuk tetap memuaskan mereka, tetapi saya tidak berpikir itu akan berguna.
Mendesain hierarki kelas yang baik itu sulit dan membutuhkan banyak wawasan tentang domain bisnis Anda. Untuk domain yang kompleks, seseorang harus membahas dua, tiga, atau bahkan lebih iterasi, karena mereka memperbaiki pemahaman mereka tentang bagaimana entitas yang berbeda dalam domain bisnis mereka berinteraksi, sampai mereka tiba pada model yang memadai.
Di situlah contoh hewan sederhana tidak ada. Kami ingin mengajar secara sederhana, tetapi masalah yang kami coba selesaikan tidak jelas sampai Anda masuk lebih dalam, yaitu memiliki pertimbangan dan domain yang lebih kompleks.
sumber