Bir sınıfı ne zaman ve neden mühürleyeceksiniz?


89

C # ve C ++ / CLI'de anahtar kelime sealed(veya NotInheritableVB'de), bir sınıfı herhangi bir kalıtım şansından korumak için kullanılır (sınıf miras alınamayacaktır). Nesne yönelimli programlamanın bir özelliğinin kalıtım olduğunu biliyorum ve kullanımının sealedbu özelliğe aykırı olduğunu, kalıtımı durdurduğunu hissediyorum . Yararını sealedve ne zaman kullanılmasının önemli olduğunu gösteren bir örnek var mı ?

Yanıtlar:


100
  1. Güvenlik özelliklerini uygulayan bir sınıfta, böylece orijinal nesnenin "kimliğine bürünemez".

  2. Daha genel olarak, son zamanlarda Microsoft'ta bir kişiyle görüştüm ve bana kalıtımı gerçekten mantıklı olduğu yerlerle sınırlandırmaya çalıştıklarını, çünkü tedavi edilmezse performans açısından pahalı hale geleceğini söyledi.
    Mühürlenmiş anahtar sözcük CLR'ye yöntem aramak için daha aşağıda bir sınıfın olmadığını ve işleri hızlandırdığını söyler.

Günümüzde piyasadaki çoğu performans artırıcı araçta, miras alınmayan tüm sınıflarınızı mühürleyecek bir onay kutusu bulacaksınız.
Yine de dikkatli olun, çünkü MEF aracılığıyla eklentilere veya derleme keşfine izin vermek istiyorsanız, sorunlarla karşılaşacaksınız.


3
Yeniden kullanılan kitaplıklardaki sınıfları kapatırken dikkatli olmayı kastetmiştim, özellikle de üçüncü taraflarca yeniden kullanılıyorlarsa ve daha sonra (MEF aracılığıyla) kod tabanına yeniden entegre ediliyorlarsa. Kod tabanınız belirli bir sınıfı devralmayabilir, ancak üçüncü şahıslar alacaktır.
Louis Kottmann

10
1 numaralı neden belirsiz gelebilir, ancak çoğu zaman "güvenlik özellikleri" yazmadığımızı varsayarsak, bu 1 numaralı nedenin pek geçerli olmadığı anlamına mı geliyor? Sebep # 2, performans ayarı içindir. Ne kadar performans farkından bahsediyoruz? Güvenlik dışı bir sınıfın tanımını değiştirmeyi haklı çıkarmak için yeterince önemli mi? Cevap "evet" olsa bile, bu ideal olarak bir derleyici seçeneği olacaktır, yani geliştiricilere kod tabanını değiştirmemizi sağlamak yerine, "mühürlenmemiş tüm sınıflar için optimize edilmiş kod üret".
RayLuo

1
performans açısından pahalı hale gelir - tedavi edilmezse bu, çılgın sayıda çılgın testten daha azıyla ölçülebilir mi?
t3chb0t

4
Sızdırmazlık berbat. Test etmeyi zorlaştırıyor - FakeItEasy ile birkaç ASP.NET sınıfıyla dalga geçmek istiyorum, ancak yapamıyorum çünkü mühürlenmişler.
Savaşçı Şempanze

2
@RayLuo ile daha fazla anlaşamıyorum. İnsanlar, güvenlik ve performansın gerçekten sorun olmadığı bir yerde sınıflarını mühürlediğini defalarca vurdum. Onların "mühürlenmesi", sınıfları geçersiz kılma ihtiyacımı basitçe engelledi, işleri çok daha zor hale getirdi. Warlike Chimpanzee'nin dediği gibi, bir sınıfla alay etmek testlerde çok yaygındır.
ZZY

15

Baboon'un mükemmel cevabına bir ek :

  1. Bir sınıf miras için tasarlanmamışsa , alt sınıflar sınıf değişmezlerini bozabilir . Bu gerçekten yalnızca genel bir API oluşturuyorsanız geçerlidir, elbette, ancak temel kural olarak, alt sınıflara ayrılmak üzere açıkça tasarlanmamış herhangi bir sınıfı mühürliyorum.

İlgili bir notta, yalnızca mühürsüz sınıflar için geçerlidir: oluşturulan herhangi bir yöntem virtualbir uzantı noktasıdır veya en azından bir uzantı noktası olması gerektiği gibi görünür. Beyan yöntemleri virtualde bilinçli bir karar olmalıdır. (C # 'da bu bilinçli bir karardır; Java'da değildir.)


DÜZENLEME : Bazı ilgili bağlantılar:

Ayrıca Kotlin'in sınıfları varsayılan olarak mühürlediğini unutmayın ; onun openkelime Java'nın tersidir finalveya sealedC # . (Elbette, bunun iyi bir şey olduğuna dair evrensel bir anlaşma yok .)


26
Sızdırmazlık sınıfları faydadan çok baş ağrısına neden olur. Sürekli olarak geliştiricilerin sınıfları mühürlediği ve basit olması gereken şeyde saatler süren zorluklara neden olan durumlar buldum. Dersleri mühürlemeyi bırak, sandığın kadar zeki değilsin. Yalnızca ZORUNLU iseniz sınıfları mühürleyin ve o zaman bile yeniden düşünün. Sadece benim fikrim, diğer insanların mühürlenmiş sınıflarıyla uğraşmak zorunda kalan adam olarak benim düzenleyemeyeceğim / mühürlemeyeceğim.
Gant Laborde

9
@GantMan'ın yorumu aslında OP'nin sorusuna verilen cevaplardan biri olarak görülmelidir, çünkü esasen "Ne zaman? Zor. Neden? Bunu yapmamanızın nedeni budur." Yorumunuzu ayrı bir cevap olarak yeniden göndermeli ve ardından bunun için oy toplamalısınız. :-)
RayLuo

1
Bu, şu yanıtı yansıtıyor muydu: stackoverflow.com/a/7777674/3195477 ?
Kişiyi

2

Bir sınıfı olarak işaretleme Sealed , güvenliği tehlikeye atabilecek veya performansı etkileyebilecek önemli sınıfların değiştirilmesini önler.

Çoğu zaman, bir sınıfı mühürlemek, değiştirmek istemediğimiz sabit davranışlı bir fayda sınıfı tasarlarken de anlamlıdır.

Örneğin, içindeki Systemad alanı C#mühürlenmiş birçok sınıf sağlar, örneğin String. Mühürlenmemişse, belirli bir işlevselliğe sahip temel bir tür olduğu için istenmeyen bir durum olabilecek işlevselliğini genişletmek mümkün olacaktır.

Benzer şekilde, structuresiçinde C#her zaman örtük olarak mühürlenir. Dolayısıyla, bir yapı / sınıf başka bir yapıdan türetilemez. Bunun nedeni , değiştirmek istemediğimiz ,structures yalnızca bağımsız, atomik, kullanıcı tanımlı veri türlerini modellemek için kullanılmasıdır .

Bazen, sınıf hiyerarşileri oluştururken, etki alanı modelinize veya iş kurallarınıza göre devralma zincirindeki belirli bir dalı sınırlamak isteyebilirsiniz.

Örneğin, a Managerve PartTimeEmployeeher ikisi de Employees'dir, ancak kuruluşunuzda yarı zamanlı çalışanlardan sonra herhangi bir rolünüz yoktur. Bu durumda, PartTimeEmployeedaha fazla dallanmayı önlemek için mühürlemek isteyebilirsiniz . Öte yandan, saatlik veya haftalık yarı zamanlı çalışanlarınız varsa, onları miras almak mantıklı olabilir PartTimeEmployee.


String sınıfını genişletmek nasıl istenmez? String hala tam olarak şu anda olduğu gibi çalışacaktı ve arzu edildiğinde ek işlevselliğe sahip türetilmiş bir sınıfa sahip olabilirsiniz, o halde hangi sorundan bahsediyorsunuz?
Kevin Wells

Ayrıca, miras hiyerarşinizi "sınırlamanın" amacı ne olabilir? Bu hiyerarşiyi genişletmeniz gerekirse, önce ebeveyn sınıfının mührünü kaldırmanız gerektiği anlamına gelir, bu sadece verimsizdir
Kevin Wells

Eric Lippert'in bu mükemmel gönderisine ve bu SO sorusuna göz atın .
Akshay Khot

1
Bu yanıt bile temelde "Neden String türetmek istersiniz?" Diye özetlenir, sonra neden String türetmek isteyebileceğinizden (örneğin boş sonlandırılmış dizeler) nedenlerden bahsetmeye devam eder ve kalıtım olmadan bunun etrafında çalışmanız gerektiğini söyler. Öyleyse neden daha karmaşık hale getirip daha sonra çözmek zorundasınız, ilk etapta onu mühürsüz bırakabilir ve seçeneklerinizi açık bırakabilirsiniz
Kevin Wells

İkinci soru için amaç istenmeyen davranışları (iş mantığına bağlı olarak) önlemek olacaktır. unsealSınıfa daha sonra, gerekirse onu mühürlemek ve ona bağlı olan tüm sınıfları kırmaktan daha kolaydır .
Akshay Khot

0

Bence bu yazının iyi bir noktası var, özel durum, herhangi bir rastgele arayüze mühürlenmemiş bir sınıf atmaya çalışırken, derleyici hata vermiyor; ancak mühürlendiğinde, derleyici dönüştüremeyeceği bir hata atar. Mühürlü sınıf, ek kod erişim güvenliği sağlar.
https://www.codeproject.com/Articles/239939/Csharp-Tweaks-Why-to-use-the-sealed-keyword-on-cla


1
Bir çözüme bağlantı memnuniyetle karşılanır, ancak lütfen cevabınızın o olmadan yararlı olduğundan emin olun: Bağlantının etrafına bağlam ekleyin, böylece kullanıcı arkadaşlarınız bunun ne olduğu ve neden orada olduğu konusunda fikir sahibi olurlar, ardından sayfanın en alakalı bölümünü alıntılayın ' hedef sayfanın mevcut olmaması durumunda yeniden bağlanma. Bir bağlantıdan biraz daha fazla olan cevaplar silinebilir.
Baum mit Augen

Maalesef cevap olarak göndermek niyetinde değildim, ancak bu diğer cevaplarla ilgili değil ve nereye koyacağımı bilmiyorum
strisunshine

1
Gönderiyi öneriye göre düzenledim. Başlangıçta sadece farklı bir açıdan katkıda bulunmak isterdim (belki), ancak yalnızca olumsuz oy aldım ve henüz içerik hakkında konuşmadık, -1 lütfen nedenini bildirebilir mi?
strisunshine
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.