Haruskah kelas tahu tentang subkelasnya?

24

Haruskah kelas tahu tentang subkelasnya? Haruskah suatu kelas melakukan sesuatu yang spesifik untuk subkelas tertentu misalnya?

Naluriku mengatakan bahwa itu adalah desain yang buruk, sepertinya semacam anti-pola.

m4design
sumber
6
Biasanya tidak, tetapi dalam kasus khusus ini berguna.
CodesInChaos
Ini adalah anti-pola, yang terkenal yang disebut: "Prinsip Pergantian Liskov" atau kadang-kadang hanya LSP, bacalah tentang hal itu di en.wikipedia.org/wiki/Liskov_substitution_principle
Jimmy Hoffa
5
@JimmyHoffa - "Prinsip Pergantian Liskov" bukan nama anti-pola. Anti-pola dapat melanggar LSP, tetapi bahkan tidak yakin apakah ini benar di sini. Ada kemungkinan bahwa, bahkan jika suatu tipe tahu itu subtipe, bahwa subtipe masih dapat diganti untuk orang tua mereka dengan contravariance dan covariance.
Matius Flynn
4
@ MatthewFlynn Mungkin saya menggunakan LSP sedikit longgar tetapi dalam definisi saya itu bukan fakta bahwa mereka semua memenuhi persyaratan satu sama lain yang sesuai dengan LSP, itu adalah persyaratan bahwa mereka memiliki decoupling sehingga tidak hanya mereka setuju dengan satu sama lain tetapi Anda bisa menerapkan subkelas lain yang tidak melanggar LSP. Jika hierarki sadar diri maka implementasi eksternal tidak mungkin memenuhi LSP tanpa mengubah kelas dasar. Mungkin itu bukan sepenuhnya LSP tetapi sangat dekat. dan ya saya seharusnya mengatakan pelanggaran LSP adalah anti-pola
Jimmy Hoffa
2
Beberapa kali saya mengalami ini, saya refactored pengetahuan itu menjadi metode yang dapat ditimpa dalam subkelas (baik dipaksa dengan membuatnya abstrak atau virtual murni, atau menyediakan implementasi standar yang masuk akal yang dapat ditimpa).

Jawaban:

32

Jawaban yang tersirat oleh konsep kelas adalah "tidak".

Entah tindakan, data, atau relasi apa pun yang Anda tangani adalah bagian dari semua subclass - maka itu harus ditangani dalam superclass tanpa memeriksa tipe yang sebenarnya. Atau itu hanya berlaku untuk beberapa subclass - maka Anda harus melakukan pemeriksaan tipe run-time untuk melakukan hal yang benar, superclass harus diubah setiap kali orang lain mewarisi darinya (atau mungkin diam-diam melakukan hal yang salah), perubahan pada kelas turunan dapat merusak superclass yang tidak berubah, dll

Singkatnya, Anda mendapatkan sejumlah konsekuensi buruk yang biasanya cukup buruk untuk menolak solusi semacam itu. Jika beberapa subclass Anda melakukan hal yang sama dan Anda ingin menghindari duplikasi kode (praktis selalu merupakan hal yang baik), solusi yang lebih baik adalah dengan memperkenalkan kelas tingkat menengah dari mana semua subclass tersebut dapat mewarisi kode.

Kilian Foth
sumber
4
Satu pengecualian untuk aturan ini: Dokumentasi kelas harus mendaftar subkelasnya secara lokal ke perpustakaannya sendiri.
Kieveli
3
@Kieveli ... selama dokumentasi itu selalu diperbarui.
mouviciel
14
Alat dokumentasi apa pun yang dapat digunakan harus dapat menggambar pohon warisan ...
johannes
13
Saya tidak berpikir itu pengecualian. Kelas masih tidak tahu apa-apa. Dokumentasi tahu.
Honza Brabec
4
@Kieveli uhh saya benar-benar tidak setuju.
Jimmy Hoffa
16

Tidak hanya seandainya tidak tahu, ia juga tidak bisa ! Biasanya, kelas dapat diperpanjang kapan saja, di mana saja. Itu dapat diperpanjang oleh kelas yang bahkan tidak ada ketika ditulis.

Beberapa bahasa memungkinkan kelas yang diperluas dikendalikan oleh superclass. Dalam Scala, sebuah kelas dapat ditandai sebagai sealed, yang berarti bahwa ia hanya dapat diperluas oleh kelas-kelas lain dalam unit kompilasi yang sama (file sumber). Namun, kecuali jika subclass tersebut juga sealed atau final, subclass kemudian dapat diperpanjang oleh kelas lain.

Dalam Scala, ini digunakan untuk memodelkan tipe data aljabar tertutup, sehingga Listtipe Haskell kanonik :

data List a = Nil | Cons a (List a)

dapat dimodelkan dalam Scala seperti ini:

sealed trait List[+A]

case object Nil extends List[Nothing]

final case class Cons[+A] extends List[A]

Dan Anda dapat menjamin bahwa hanya dua sub "kelas" yang ada karena Listini sealeddan dengan demikian tidak dapat diperpanjang di luar file, Consadalah finaldan dengan demikian tidak dapat diperpanjang sekali dan Nilmerupakan objectyang tidak dapat diperpanjang pula.

Tapi ini adalah kasus penggunaan khusus (pemodelan tipe data aljabar melalui pewarisan) dan bahkan dalam kasus ini, superclass tidak benar-benar tahu tentang subkelasnya. Ini lebih jaminan kepada pengguna dari Listjenis bahwa jika ia melakukan diskriminasi kasus Nildan Cons, ada tidak akan ada lain alternatif bermunculan di belakang punggungnya.

Jörg W Mittag
sumber
Apa yang berfungsi dalam banyak bahasa adalah menambahkan beberapa bentuk abstract internalanggota.
CodesInChaos
4

Jawaban sederhananya adalah TIDAK.

Itu membuat kode rapuh dan merusak dua prinsip dasar pemrograman berorientasi objek.

  • Prinsip Pergantian Liskov
  • Prinsip Buka Tutup
Sajad Deyargaroo
sumber
1

Ya kadang kadang. Misalnya, ketika ada jumlah subclass yang terbatas. Sebuah pola pengunjung adalah sebuah ilustrasi dari kegunaan pendekatan ini.

Contoh: node sintaksis abstrak (AST) dari beberapa tata bahasa yang terdefinisi dengan baik dapat diwarisi dari Nodekelas tunggal yang menerapkan pola pengunjung untuk menangani semua tipe simpul.

Lorus
sumber
9
Tidak, tidak dan tidak. Ini tidak berguna dan tidak pernah merupakan solusi yang baik.
Sulthan
@Sulthan Saya telah bekerja dengan AST di luar kelas, dan saya percaya Lorus tidak benar-benar mengerti pertanyaannya. Pengunjung bukan tipe node pada AST, itu adalah objek yang terpisah. Itu bisa dan harus tahu tentang benda-benda tata bahasa. Tetapi simpul AST tingkat tinggi seharusnya tidak.
1
@JohnGaughan Istilah "tahu" membingungkan saya. Kelas dasar Node, tentu saja, tidak mengandung referensi langsung ke subkelasnya. Tetapi itu berisi acceptmetode dengan Visitorparameter. Dan Visitorberisi visitmetode per setiap subclass. Jadi, meskipun Nodetidak memiliki referensi langsung ke subkelasnya, ia "tahu" tentang mereka secara tidak langsung, melalui Visitorantarmuka. Mereka semua digabungkan bersama-sama melaluinya.
Lorus
1
@Sulthan Never say never. Jenis opsi adalah contoh yang valid dari kasus ketika supreclass tahu tentang keturunan. Tapi seperti yang dikatakan Jorg itu akan ditandai sebagai disegel.
Pavel Voronin
Kemudian setuju: pengunjung perlu tahu apa yang dikunjungi.
1

Jika saya menulis komponen untuk sebuah perusahaan dan kemudian, setelah saya pergi, seseorang memperluasnya untuk keperluan mereka sendiri, haruskah saya diberitahu tentang itu?

Tidak!

Sama dengan kelas. Percaya dengan nalurimu.

Daniel Hollinrake
sumber
Keamanan kerja???
sixtyfootersdude
Tinggimu enam puluh kaki jadi saya tidak akan berdebat dengan Anda :-) Namun, saya harap maksud saya adalah setelah saya pergi dan mendapatkan pekerjaan lain.
Daniel Hollinrake