Saya memiliki beberapa kode di mana model pewarisan yang baik telah menurun dan saya mencoba memahami mengapa dan bagaimana cara memperbaikinya. Pada dasarnya, bayangkan Anda memiliki hierarki Kebun Binatang dengan:
class Animal
class Parrot : Animal
class Elephant : Animal
class Cow : Animal
dll.
Anda memiliki metode eat (), run (), dll, dan semuanya baik-baik saja. Kemudian suatu hari seseorang datang dan berkata - kelas CageBuilder kami berfungsi dengan baik dan menggunakan animal.weight () dan animal.height (), kecuali untuk Bison Afrika baru yang terlalu kuat dan dapat menghancurkan dinding, jadi saya akan menambahkan satu lagi properti ke kelas Animal - isAfricanBizon () dan menggunakannya saat memilih materi dan hanya menimpanya untuk kelas AfricanBizon. Orang berikutnya datang dan melakukan sesuatu yang serupa dan selanjutnya Anda tahu Anda memiliki semua properti ini khusus untuk beberapa subset hierarki ke dalam kelas dasar.
Apa cara yang baik untuk meningkatkan / memperbaiki kode semacam itu? Salah satu alternatif di sini adalah dengan hanya menggunakan dynamic_casts untuk memeriksa jenis tetapi itu mengacaukan penelepon dan menambahkan sekelompok if-then-else di semua tempat. Anda dapat memiliki antarmuka yang lebih spesifik di sini tetapi jika semua yang Anda miliki adalah referensi kelas dasar yang tidak banyak membantu. Ada saran lain? Contohnya?
Terima kasih!
sumber
Jawaban:
Sepertinya masalahnya adalah alih-alih menerapkan WajibConcreteWall (), mereka menerapkan panggilan bendera IsAfricanBison (), dan kemudian memindahkan logika tentang apakah dinding harus berubah di luar ruang lingkup kelas. Kelas Anda harus memaparkan perilaku dan persyaratan, bukan identitas; konsumen Anda dari kelas-kelas ini harus bekerja berdasarkan apa yang diperintahkan, bukan berdasarkan apa yang mereka katakan.
sumber
isAfricanBizon () tidak generik. Misalkan Anda memperluas peternakan hewan Anda dengan hyppopotamus yang juga terlalu kuat tetapi mengembalikan true dari isAfricanBizon () untuk memiliki efek yang tepat akan konyol.
Anda selalu ingin menambahkan metode ke antarmuka yang menjawab pertanyaan spesifik, dalam hal ini akan menjadi sesuatu seperti kekuatan ()
sumber
strength
metode dapat ditanyakan denganmaterial.canHold(animal)
, memungkinkan cara yang bersih untuk mendukung berbagai jenis bahan daripadaConcreteWall
.Saya pikir masalah Anda adalah ini: Anda memiliki berbagai klien perpustakaan yang tertarik hanya sebagian dari hirarki tetapi yang melewati pointer / referensi ke kelas dasar. Itu sebenarnya masalah yang dynamic_cast <> ada untuk dipecahkan.
Ini adalah masalah desain klien untuk meminimalkan penggunaan dynamic_cast <>; mereka harus menggunakannya untuk menentukan apakah objek memerlukan perlakuan khusus dan jika demikian lakukan semua operasi pada referensi yang dicor.
Jika Anda memiliki koleksi fungsi "campuran" yang berlaku untuk beberapa sub hierarki yang terpisah, Anda mungkin ingin menggunakan pola antarmuka yang digunakan Java dan C #; memiliki kelas dasar virtual yang merupakan kelas virtual-murni, dan gunakan dynamic_cast <> untuk menentukan apakah instance menyediakan implementasi untuknya.
sumber
Satu hal yang dapat Anda lakukan adalah mengganti pemeriksaan tipe secara eksplisit seperti
isAfricanBison()
dengan memeriksa properti yang sebenarnya Anda minati, yaituisTooStrong()
.sumber
Hewan seharusnya tidak peduli dengan dinding beton. Mungkin Anda bisa mengungkapkannya dengan nilai-nilai sederhana.
Saya kira itu tidak layak. Itulah masalah dengan contoh mainan.
Saya tidak akan pernah ingin melihat MemerlukanConcreteWalls () atau garis dan garis gips pointer dinamis pada tingkat apapun.
Ini biasanya solusi yang murah . Sangat mudah untuk mempertahankan dan membuat konsep. Dan sungguh, masalahnya menyatakan bahwa itu terkait dengan jenis hewan.
Ini tidak menghalangi Anda untuk menggunakan kode bersama, cukup mencemari Hewan sedikit.
Tetapi bagaimana kandang dibangun mungkin merupakan kebijakan dari beberapa sistem lain, dan mungkin Anda memiliki lebih dari satu jenis pembangun kandang per hewan. Ada banyak kombinasi aneh dan berbelit-belit yang bisa Anda buat.
Saya telah menggunakan Desain Berbasis Komponen untuk tujuan yang baik, masalah utamanya adalah bahwa hal itu dapat menyulitkan ketika kepemilikan Hewan dibagikan. Bagaimana menghindari melempar destruktor menjadi titik rasa sakit.
Double Dispatch adalah pilihan lain, meskipun saya selalu ragu untuk menerimanya.
Di luar itu sulit untuk menebak masalahnya.
sumber
Yah pasti semua Hewan memiliki properti bawaan
attemptEscape()
. Sementara beberapa metode dapat menimbulkanfalse
hasil dalam semua skenario sementara yang lain mungkin memiliki kesempatan berdasarkan heuristik karakteristik intrinsik mereka yang lain sepertisize
danweight
. Maka tentu saja di beberapa titikattemptEscape()
menjadi sepele karena pasti akan kembalitrue
.Saya khawatir saya tidak sepenuhnya memahami pertanyaan Anda ... semua hewan memiliki tindakan dan karakteristik yang terkait. Yang khusus untuk hewan harus diperkenalkan di tempat yang cocok. Mencoba menghubungkan langsung Bison dengan Parrots bukanlah pengaturan bawaan yang baik dan seharusnya tidak menjadi masalah dalam desain yang tepat.
sumber
Pilihan lain adalah menggunakan pabrik yang membuat kandang yang sesuai untuk setiap hewan. Saya pikir ini bisa lebih baik jika kondisinya sangat berbeda untuk masing-masing. Tetapi jika hanya kondisi ini saja
RequiresConcreteWall()
metode yang disebutkan di atas akan melakukannya.sumber
bagaimana dengan RecommendCageType () sebagaimana oppsed ke MembutuhkanConcreteWall ()
sumber
Kenapa tidak melakukan hal seperti ini
class Animals { /***/ } class HeavyAnimals{} : Animals //The basic class for animals like the African Bison
Dengan kelas HeavyAnimals, Anda dapat membuat kelas African Bison dengan memperluas kelas HeavyAnimals.
Jadi sekarang Anda kelas induk (Hewan) yang dapat digunakan untuk membuat kelas dasar lainnya seperti kelas HeavyAnimal dengan dapat digunakan untuk membuat kelas Bison Afrika dan Hewan Berat lainnya. Jadi dengan Bison Afrika Anda sekarang memiliki akses ke metode dan properti kelas Hewan (ini adalah basis untuk semua hewan) dan akses ke kelas HeavyAnimal (ini adalah dasar untuk Hewan Berat)
sumber