Kapan dan mengapa Anda menutup kelas?

89

Dalam C # dan C ++ / CLI kata kunci sealed(atau NotInheritabledalam VB) digunakan untuk melindungi kelas dari kemungkinan pewarisan (kelas tidak dapat diwariskan). Saya tahu bahwa salah satu fitur pemrograman berorientasi objek adalah pewarisan dan saya merasa bahwa penggunaan dari sealedbertentangan dengan fitur ini, ia menghentikan pewarisan. Apakah ada contoh yang menunjukkan manfaat sealeddan kapan penggunaannya penting?

Aan
sumber

Jawaban:

100
  1. Di kelas yang menerapkan fitur keamanan, sehingga objek asli tidak dapat "ditiru".

  2. Secara lebih umum, baru-baru ini saya bertukar pikiran dengan seseorang di Microsoft, yang mengatakan kepada saya bahwa mereka mencoba membatasi warisan ke tempat-tempat yang benar-benar masuk akal, karena akan menjadi mahal dari segi kinerja jika tidak ditangani.
    Kata kunci tersegel memberi tahu CLR bahwa tidak ada kelas lebih jauh ke bawah untuk mencari metode, dan itu mempercepat segalanya.

Di sebagian besar alat peningkat kinerja di pasaran saat ini, Anda akan menemukan kotak centang yang akan menutup semua kelas Anda yang tidak diwariskan.
Berhati-hatilah, karena jika Anda ingin mengizinkan penemuan plugin atau perakitan melalui MEF, Anda akan mengalami masalah.

Louis Kottmann
sumber
3
Maksud saya berhati-hati dengan menyegel kelas di perpustakaan yang digunakan kembali, terutama jika mereka digunakan kembali oleh pihak ketiga dan kemudian diintegrasikan kembali (melalui MEF) ke dalam basis kode. Basis kode Anda mungkin tidak mewarisi kelas tertentu tetapi pihak ketiga akan mewarisi.
Louis Kottmann
10
Alasan # 1 terdengar tidak jelas tetapi, dengan asumsi kami tidak menulis "fitur keamanan" hampir sepanjang waktu, apakah itu berarti alasan # 1 hampir tidak berlaku? Alasan # 2 adalah untuk penyempurnaan kinerja. Seberapa besar perbedaan kinerja yang sedang kita bicarakan? Apakah mereka cukup signifikan untuk membenarkan perubahan definisi kelas non-keamanan? Bahkan jika jawabannya adalah "ya", idealnya ini adalah opsi kompiler yaitu "menghasilkan kode yang dioptimalkan untuk semua kelas yang tidak tersegel", daripada meminta kami sebagai pengembang untuk mengubah basis kode.
RayLuo
1
menjadi mahal dari segi kinerja jika tidak ditangani apakah ini bahkan dapat diukur dengan jumlah tes gila yang kurang dari itu?
t3chb0t
4
Sealing menyebalkan. Itu membuat pengujian lebih sulit - Saya ingin mengejek beberapa kelas ASP.NET dengan FakeItEasy, tetapi saya tidak bisa karena mereka disegel.
Simpanse yang Suka Berperang
2
Sangat setuju dengan @RayLuo. Saya memukulnya beberapa kali sehingga orang-orang menyegel kelas mereka di mana keamanan dan kinerja sebenarnya bukan masalah. "Dimeteraikan" mereka hanya menghalangi kebutuhan masuk akal saya untuk mengesampingkan kelas, membuat segalanya jauh lebih sulit. Seperti yang dikatakan Simpanse Seperti Perang, mengejek kelas sangat umum dalam pengujian.
ZZY
15

Tambahan dari jawaban luar biasa Baboon :

  1. Jika kelas tidak dirancang untuk warisan, subkelas mungkin merusak invarian kelas . Ini benar-benar hanya berlaku jika Anda membuat API publik, tentu saja, tetapi seperti yang saya pegang teguh, saya menutup kelas apa pun yang tidak secara eksplisit dirancang untuk dijadikan subkelas.

Pada catatan terkait, hanya berlaku untuk kelas yang tidak disegel: metode apa pun yang dibuat virtualadalah titik ekstensi, atau setidaknya terlihat seperti itu harus menjadi titik ekstensi. Mendeklarasikan metode virtualharus menjadi keputusan sadar juga. (Di C # ini adalah keputusan sadar; di Jawa tidak.)


EDIT : Beberapa tautan yang relevan:

Perhatikan juga bahwa Kotlin menyegel kelas secara default; nya openkata kunci adalah kebalikan dari Jawa finalatau sealedC # . (Yang pasti, tidak ada kesepakatan universal bahwa ini adalah hal yang baik .)

Petter Hesselberg
sumber
26
Kelas penyegelan menyebabkan lebih banyak sakit kepala daripada manfaat. Saya terus menemukan situasi di mana pengembang telah menyegel kelas, menyebabkan saya kesulitan berjam-jam dalam hal yang seharusnya sederhana. Berhenti menyegel kelas, Anda tidak secerdas yang Anda kira. Segel kelas hanya jika Anda HARUS, dan bahkan kemudian, pertimbangkan kembali. Hanya pendapat saya, sebagai orang yang harus berurusan dengan kelas tersegel orang lain yang tidak dapat saya edit / buka segelnya.
Gant Laborde
9
Komentar @GantMan sebenarnya harus dianggap sebagai salah satu jawaban atas pertanyaan OP, karena pada intinya memberikan jawaban "Kapan? Hampir tidak. Kenapa? Inilah alasan mengapa Anda TIDAK melakukan itu." Berikan Anda harus memposting ulang komentar Anda sebagai jawaban terpisah dan kemudian mengumpulkan suara untuk itu. :-)
RayLuo
1
Apakah ini mengacu pada jawaban ini: stackoverflow.com/a/7777674/3195477 ? Lebih baik menautkannya daripada (hanya) menyebutkan nama orangnya
UuDdLrLrSs
2

Menandai kelas sebagai Sealedmencegah perusakan kelas penting yang dapat membahayakan keamanan, atau memengaruhi kinerja.

Seringkali, menyegel kelas juga masuk akal ketika seseorang mendesain kelas utilitas dengan perilaku tetap, yang tidak ingin kita ubah.

Misalnya, Systemnamespace di C#menyediakan banyak kelas yang disegel, seperti String. Jika tidak disegel, dimungkinkan untuk memperluas fungsinya, yang mungkin tidak diinginkan, karena ini adalah tipe dasar dengan fungsionalitas tertentu.

Demikian pula, structuresin C#selalu tersegel secara implisit. Karenanya seseorang tidak dapat memperoleh satu struktur / kelas dari struktur lain. Alasan untuk ini adalah yang structuresdigunakan untuk memodelkan hanya tipe data yang berdiri sendiri, atom, dan ditentukan pengguna , yang tidak ingin kita modifikasi.

Terkadang, saat Anda membangun hierarki kelas, Anda mungkin ingin menutup cabang tertentu dalam rantai warisan, berdasarkan model domain atau aturan bisnis Anda.

Misalnya, a Managerdan PartTimeEmployeekeduanya Employees, tetapi Anda tidak memiliki peran apa pun setelah karyawan paruh waktu di organisasi Anda. Dalam kasus ini, Anda mungkin ingin menyegel PartTimeEmployeeuntuk mencegah percabangan lebih lanjut. Di sisi lain, jika Anda memiliki karyawan paruh waktu per jam atau mingguan, mungkin masuk akal untuk mewarisi mereka PartTimeEmployee.

Akshay Khot
sumber
Bagaimana memperluas kelas String menjadi tidak diinginkan? String akan tetap berfungsi seperti saat ini, dan Anda dapat memiliki kelas turunan dengan fungsionalitas tambahan jika diinginkan, jadi masalah apa yang Anda bicarakan?
Kevin Wells
Juga apa gunanya "membatasi" hierarki warisan Anda? Ini berarti bahwa jika Anda memang perlu memperluas hierarki itu, Anda harus membuka segel kelas induk terlebih dahulu, yang tidak efisien
Kevin Wells
Lihat posting luar biasa ini dari Eric Lippert dan pertanyaan SO ini .
Akshay Khot
1
Bahkan jawaban itu pada dasarnya bermuara pada "Mengapa Anda ingin mendapatkan String?", Kemudian melanjutkan dengan menyebutkan alasan mengapa Anda mungkin ingin mendapatkan String (string yang diakhiri dengan null misalnya) dan mengatakan Anda harus mengatasinya tanpa pewarisan. Jadi mengapa membuatnya lebih rumit dan harus mengatasinya nanti ketika Anda bisa membiarkannya terbuka dan membiarkan pilihan Anda terbuka
Kevin Wells
Untuk pertanyaan kedua, tujuannya adalah untuk mencegah perilaku yang tidak diinginkan (bergantung pada logika bisnis). Lebih mudah untuk unsealkelas nanti, jika diperlukan, daripada menyegelnya dan menghancurkan semua kelas yang bergantung padanya.
Akshay Khot
0

Saya pikir posting ini memiliki beberapa poin yang baik, kasus spesifiknya adalah ketika mencoba mentransmisikan kelas yang tidak disegel ke antarmuka acak apa pun, kompiler tidak membuang kesalahan; tetapi ketika disegel digunakan, kompilator mengeluarkan kesalahan yang tidak dapat diubah. Kelas tertutup membawa keamanan akses kode tambahan.
https://www.codeproject.com/Articles/239939/Csharp-Tweaks-Why-to-use-the-sealed-keyword-on-cla

strisunshine
sumber
1
Tautan ke solusi diperbolehkan, tetapi harap pastikan jawaban Anda berguna tanpanya: tambahkan konteks di sekitar tautan sehingga sesama pengguna Anda akan tahu apa itu dan mengapa itu ada, kemudian kutip bagian paling relevan dari halaman Anda ' menautkan ulang jika halaman target tidak tersedia. Jawaban yang tidak lebih dari sebuah tautan dapat dihapus.
Baum mit Augen
Maaf saya tidak bermaksud untuk mempostingnya sebagai jawaban, tetapi sepertinya tidak terkait dengan jawaban lain dan saya tidak tahu harus meletakkannya di mana
strisunshine
1
Saya mengedit posting sesuai saran. Awalnya saya hanya ingin memberikan sudut pandang yang berbeda (mungkin), tetapi saya hanya mendapat downvote dan kami belum membicarakan kontennya, bisakah yang -1 dengan ramah memberi tahu alasannya?
strisunshine