Saya percaya alasan sebenarnya banyak orang merasa kelas harus final
/ sealed
adalah bahwa sebagian besar kelas diperpanjang non-abstrak tidak didokumentasikan dengan baik .
Biarkan saya uraikan. Mulai dari jauh, ada pandangan di antara beberapa programmer bahwa pewarisan sebagai alat dalam OOP banyak digunakan dan disalahgunakan. Kita semua telah membaca prinsip substitusi Liskov, meskipun ini tidak menghentikan kita untuk melanggarnya ratusan (bahkan mungkin ribuan) kali.
Masalahnya adalah programmer suka menggunakan kembali kode. Bahkan ketika itu bukan ide yang bagus. Dan pewarisan adalah alat utama dalam kode "reabusing" ini. Kembali ke pertanyaan terakhir / tertutup.
Dokumentasi yang tepat untuk kelas akhir / tertutup relatif kecil: Anda menggambarkan apa yang dilakukan masing-masing metode, apa argumennya, nilai baliknya, dll. Semua hal yang biasa.
Namun, ketika Anda mendokumentasikan dengan benar kelas yang dapat diperpanjang, Anda harus memasukkan setidaknya yang berikut ini :
- Ketergantungan antara metode (metode mana yang memanggil, dll.)
- Ketergantungan pada variabel lokal
- Kontrak internal yang harus dihormati oleh kelas yang diperluas
- Panggilan konvensi untuk setiap metode (mis. Ketika Anda menimpanya, apakah Anda memanggil
super
implementasi? Apakah Anda menyebutnya di awal metode, atau pada akhirnya? Pikirkan konstruktor vs destruktor)
- ...
Ini hanya dari atas kepala saya. Dan saya dapat memberi Anda sebuah contoh mengapa masing-masing ini penting dan melewatkannya akan mengacaukan kelas yang diperluas.
Sekarang, pertimbangkan berapa banyak upaya dokumentasi yang harus dilakukan untuk mendokumentasikan dengan baik masing-masing hal ini. Saya percaya kelas dengan 7-8 metode (yang mungkin terlalu banyak di dunia ideal, tetapi terlalu sedikit di dunia nyata) mungkin juga memiliki dokumentasi sekitar 5 halaman, hanya teks. Jadi, sebagai gantinya, kita keluar setengah jalan dan tidak menyegel kelas, sehingga orang lain dapat menggunakannya, tetapi jangan mendokumentasikannya dengan baik, karena itu akan memakan banyak waktu (dan, Anda tahu, itu mungkin tidak pernah diperpanjang, jadi mengapa repot-repot?).
Jika Anda mendesain sebuah kelas, Anda mungkin merasakan godaan untuk menutupnya sehingga orang tidak dapat menggunakannya dengan cara yang tidak Anda perkirakan (dan siapkan untuk). Di sisi lain ketika Anda menggunakan kode orang lain, kadang-kadang dari API publik tidak ada alasan yang kelihatan untuk kelas menjadi final, dan Anda mungkin berpikir "Sial, ini hanya menghabiskan waktu 30 menit untuk mencari solusi".
Saya pikir beberapa elemen dari solusi adalah:
- Pertama-tama untuk memastikan perluasan adalah ide yang baik ketika Anda adalah klien dari kode, dan untuk benar - benar menyukai komposisi daripada warisan.
- Kedua untuk membaca manual secara keseluruhan (lagi sebagai klien) untuk memastikan Anda tidak mengabaikan sesuatu yang disebutkan.
- Ketiga, ketika Anda menulis sepotong kode yang akan digunakan klien, tulis dokumentasi yang tepat untuk kode tersebut (ya, jauh). Sebagai contoh positif, saya bisa memberikan dokumen Apple iOS. Mereka tidak cukup bagi pengguna untuk selalu memperluas kelas mereka dengan benar, tetapi mereka setidaknya menyertakan beberapa informasi tentang warisan. Yang lebih dari yang bisa saya katakan untuk sebagian besar API.
- Keempat, benar-benar mencoba memperluas kelas Anda sendiri, untuk memastikan itu berfungsi Saya adalah pendukung besar untuk menyertakan banyak sampel dan tes dalam API, dan ketika Anda melakukan tes, Anda mungkin juga menguji rantai pewarisan: mereka adalah bagian dari kontrak Anda setelah semua!
- Kelima, dalam situasi ketika Anda ragu, tunjukkan bahwa kelas tidak dimaksudkan untuk diperpanjang dan melakukannya adalah ide yang buruk (tm). Tunjukkan bahwa Anda seharusnya tidak dimintai pertanggungjawaban atas penggunaan yang tidak diinginkan tersebut, tetapi tetap tidak menyegel kelas. Jelas, ini tidak mencakup kasus ketika kelas harus 100% disegel.
- Akhirnya, saat menyegel kelas, sediakan antarmuka sebagai pengait perantara, sehingga klien dapat "menulis ulang" versi modifikasi kelasnya sendiri dan mengerjakan kelas 'tersegel' Anda. Dengan cara ini, ia dapat mengganti kelas yang disegel dengan implementasinya. Sekarang, ini harus jelas, karena longgar dalam bentuk paling sederhana, tetapi masih layak disebutkan.
Perlu juga disebutkan pertanyaan "filosofis" berikut: Apakah suatu kelas merupakan sealed
/ final
bagian dari kontrak untuk kelas tersebut, atau detail implementasi? Sekarang saya tidak ingin menginjak sana, tetapi jawaban untuk ini juga harus mempengaruhi keputusan Anda apakah akan menutup kelas atau tidak.
Open/Closed principle
, bukanClosed Principle.