Kapan harus menggunakan warisan, kapan harus menggunakan 'hanya bidang boolean'?

18

Dalam aplikasi Rails kami, kami menambahkan pemberitahuan. Beberapa di antaranya adalah blocking: Mereka menghentikan kemajuan sumber daya apa pun yang mereka tambahkan, karena beberapa informasi tentang sumber daya itu hilang.

Pemberitahuan lainnya adalah pemberitahuan sederhana, dan hanya memberikan informasi.

Hari ini saya berdiskusi dengan programmer lain di tim kami. Saya telah membuat struktur warisan seperti ini:

masukkan deskripsi gambar di sini

Namun dia, lebih suka saya hanya menambahkan blockingsebagai metode pengembalian boolean pada setiap Pemberitahuan, dan tentukan daftar subkelas yang memblokir di dalam kelas induk Pemberitahuan.

Perbedaan antara pendekatan ini tidak terlalu besar; dalam pendekatan saya seseorang tidak harus menentukan daftar ini, menjaga pembersih kelas root. Di sisi lain, logika khusus yang terjadi Notification::Blockingsaat ini juga tidak terlalu besar.

Jenis abstraksi apa yang lebih cocok untuk masalah ini?

Qqwy
sumber
11
Kelas orang tua seharusnya tidak pernah tahu tentang anak-anak itu. Mengapa Anda perlu menyimpan daftar sub-kelas?
coteyr
Bagaimana mereka ditambahkan pada sumber daya dan bagaimana mereka menghentikan kemajuannya?
null
3
Mengapa Anda membutuhkan begitu banyak kelas notifikasi? Bagi saya sepertinya Anda bisa membuat satu kelas notifikasi, lalu biarkan data yang mendorong tindakan alih-alih tipe data.
Dipotong
1
@Trisped: benar, jika Anda menemukan diri Anda memindahkan satu aspek perilaku ke kelas dasar dengan daftar kasus yang lengkap, maka miliki keberanian untuk keyakinan Anda, akui bahwa Anda tidak benar-benar merancang kelas dasar yang dapat digunakan untuk penyesuaian dengan ekstensi. , dan pindahkan semua perilaku ke kelas dasar!
Steve Jessop

Jawaban:

35

Anda ingin menghindari kelas dasar mengetahui tentang kelas turunan. Ini memperkenalkan kopling ketat dan merupakan sakit kepala pemeliharaan karena Anda harus ingat untuk menambahkan ke daftar setiap kali Anda membuat kelas turunan baru.

Ini juga akan mencegah Anda untuk dapat menempatkan kelas Notifikasi ke dalam paket / perakitan yang dapat digunakan kembali jika Anda ingin menggunakan kelas ini di beberapa proyek.

Jika Anda benar-benar ingin menggunakan kelas basis tunggal, cara lain untuk menyelesaikan ini adalah dengan menambahkan properti virtual atau metode IsBlocking pada kelas Pemberitahuan dasar. Kelas turunan kemudian dapat menimpanya untuk mengembalikan benar atau salah. Anda akan memiliki solusi kelas tunggal tanpa kelas dasar mengetahui tentang kelas turunan.

17 dari 26
sumber
3
Ini. Buat keputusan di satu tempat. Jangan menyebarkan pengetahuan tentang kelas mana yang menghalangi antara kelas dan daftar.
candied_orange
Ini yang saya lakukan, bekerja dengan sangat baik dan sangat dapat digunakan kembali.
coteyr
13

dan tentukan daftar subclass yang memblokir di dalam kelas induk Notification.

Itu terlihat sangat aneh dan merupakan bau kode tertentu.

Saya akan memberikan subkelas jika Anda memiliki perbedaan perilaku di antara kelas-kelas, dan Anda ingin memperlakukan semua pemberitahuan ini dengan cara yang sama (yaitu menggunakan polimorfisme ).

Brian Agnew
sumber
1
Saya pikir "perilaku" adalah kuncinya di sini: ketika itu hanya data, bidang tersebut harus menjadi pembeda yang memadai. Perilaku adalah alasan yang lebih baik untuk menggunakan polimorfisme namun orang harus selalu mempertimbangkan kompleksitas pemeliharaan saat membuat hierarki warisan. Baca en.wikipedia.org/wiki/Composition_over_inheritance
cottsak
7

Sebagai kebalikan dari jawaban yang ada, saya akan menyarankan bahwa properti boolean adalah pilihan terbaik jika mode yang akan digunakan harus diubah secara dinamis (misalnya melalui file konfigurasi yang memberikan daftar jenis yang akan diblokir. dan yang tidak).

Yang mengatakan, desain yang lebih baik bahkan dalam situasi ini mungkin menggunakan objek Dekorator.

Jules
sumber
1

Saya akan mengatakan itu tergantung pada seberapa banyak hal khusus tentang pemberitahuan pemblokiran, meskipun pemikiran pertama saya adalah pergi dengan "keduanya":

class Notification
 virtual Boolean Blocking{get return false;}

class BlockingNotification inherits Notification
 virtual overrides Boolean Blocking{get return true;}

Dengan begitu, Anda bisa menggunakan n.Blockingatau n is BlockingNotification(semua dalam pseudo-code), meskipun, jika Anda akan mengizinkan kelas untuk menerapkan nilai konteks-sensitif Blocking, mengingat Anda harus memeriksa nilai itu setiap kali, BlockingNotificationkelas menjadi kurang bermanfaat.

Bagaimanapun, saya setuju dengan jawaban lain bahwa Anda tidak ingin implementasi kelas dasar Blockingharus tahu tentang kelas turunan.

Mark Hurd
sumber
0

Alih-alih membuat dua kelas dasar dan beberapa instance masing-masing, buat satu kelas notifikasi dengan bool untuk menunjukkan apakah notifikasi tersebut memblokir dan informasi lain yang diperlukan untuk mengkomunikasikan notifikasi kepada pengguna.

Ini memungkinkan Anda untuk menggunakan satu set kode untuk memproses dan menyajikan notifikasi dan mengurangi kompleksitas kode Anda.

Berbilah
sumber