Bir sınıfta 'final'i kullanmak neden bu kadar kötü?


34

Bir PHP OOP eski web sitesini yeniden gözden geçiriyorum.

"Final" dersini " make it explicit that the class is currently not extended by anything" ile kullanmaya başlıyorum . Bir sınıfa gelirsem çok zaman kazandırabilir ve bir protectedözelliği veya yöntemi yeniden adlandırabilir / silebilir / değiştirebilir miyim diye merak ediyorum . Eğer bir sınıfı gerçekten genişletmek istersem, genişletmek için kilidini açmak üzere son anahtar kelimeyi kaldırabilirim .

Yani, çocuk sınıfı olmayan bir sınıfa gelirsem, bu bilgiyi sınıfa final olarak işaretleyerek kaydedebilirim. Bir dahaki sefere geldiğimde, çocukları olup olmadığını görmek için kod tabanını tekrar aramak zorunda kalmayacağım. Böylece yeniden yapılanmalar sırasında zaman kazanır.

Her şey mantıklı bir zaman tasarrufu fikri gibi gözüküyor ... ama çoğu zaman sınıfların nadir / özel durumlarda sadece 'final' yapılması gerektiğini okudum.

Belki Mock nesnesinin yaratılmasını berbat ediyor ya da düşünmediğim başka yan etkileri de var.

Neyi kaçırıyorum?


3
Kodunuzu tam olarak kontrol ediyorsanız, o zaman korkunç değil, sanırım bir OKB tarafında. Bir dersi kaçırırsanız (örneğin çocuğu yok ama finali olmadıysa)? Bir aracın kodu taramasına izin verin ve bazı sınıfların çocukları olup olmadığını söyleyin. Bunu bir kütüphane olarak paketleyip bir başkasına verdiğinizde, 'final' ile uğraşmak acı verir.
İş

Örneğin, MbUnit .Net birim testi için açık bir çerçevedir ve MsTest değildir (sürpriz bir sürpriz). Sonuç olarak, bazı testleri MSFT yolunda çalıştırmak istediğiniz için 5k’yı MSFT’e bağlamanız gerekir. Diğer test koşucuları, MSFT'nin kullandığı son sınıflar nedeniyle MsTest ile oluşturulan test dll'sini çalıştıramazlar.
Meslek

3
Konu hakkında bazı blog yazısı: Final Sınıfları: Genişlemeye Açık, Mirasa Kapalı (Mayıs 2014; Mathias Verraes tarafından)
hakre

Güzel makale. Bu konuda düşüncelerimi konuşuyor. Bu ek açıklamaları bilmiyordum, bu yüzden kullanışlıydı. Şerefe.
JW01

"PHP 5, alt sınıfın tanımı ile ön ek ekleyerek alt sınıfların bir yöntemi geçersiz kılmasını önleyen son anahtar sözcüğü sunar. Sınıfın kendisi son tanımlıysa, genişletilemez." php.net/manual/en/language.oop5.final.php Hiç fena değil.
Siyah

Yanıtlar:


54

Sınıfların nadir / özel durumlarda sadece 'final' yapılması gerektiğini sık sık okudum.

Bunu kim yazdıysa yanlış. finalLiberal kullan , bunda yanlış bir şey yok. Bir sınıfın kalıtımsal olarak düşünülmediğini belgelemektedir ve bu genellikle varsayılan olarak tüm sınıflar için doğrudur: anlamlı bir şekilde miras alınabilecek bir sınıf tasarlamak, yalnızca bir finalbelirticiyi kaldırmaktan daha fazlasını gerektirir ; çok özen gösterir.

Yani finalvarsayılan olarak kullanmak hiçbir şekilde kötü değildir. Aslında, birçok insan bunun varsayılan olması gerektiğini önermektedir, örneğin Jon Skeet .

Belki Mock nesnesinin yaratılmasını mahveder…

Bu gerçekten bir uyarıdır, ancak sınıflarınızla alay etmeniz gerektiğinde arayüzlere her zaman başvurabilirsiniz. Bu, tüm sınıfları sadece alay etme amacıyla mirasa açık hale getirmekte kesinlikle üstündür.


1
1+: Alay konusu berbat ettiğinden; Her "final" sınıfı için arayüzler veya soyut sınıflar oluşturmayı düşünün.
Spoike

Peki bu işlere bir anahtar koyar. Bu geç varış diğer tüm cevaplarla çelişmektedir. Şimdi neye inanacağımı bilmiyorum: o. (Kabul edilmiş cevabımın işaretlenmemiş ve yeniden yargılama sırasında kararın geri alınması)
JW01

1
Java API'sinin kendisini ve 'final' anahtar kelimenin kullanımını ne sıklıkta bulacağınızı düşünebilirsiniz. Aslında, çok sık kullanılmaz. "Sanal" yöntemler çağrıldığında (Java’da tüm yöntemler sanaldır) ya da "özel" olarak bildirilmezlerse, tüm sanal uygulamalarda sanal olarak kullanıldığında gerçekleşen dinamik bağlanma nedeniyle performansın kötüye gidebileceği durumlarda kullanılır. Java API sınıfının alt sınıfları, 'java.lang.String' alt sınıflaması gibi tutarlılık sorunları ortaya çıkabilir. Bir Java String, tanım başına bir değer nesnesidir ve daha sonra değerini değiştirmemelidir. Bir alt sınıf bu kuralı kırabilir.
Jonny Dee,

5
@Jonny Java API'sinin çoğu kötü tasarlanmıştır. Bunların büyük bölümünün on yaşından büyük olduğunu ve bu arada en iyi uygulamaların geliştirildiğini unutmayın. Ancak benim sözüme kapılma: Java mühendisleri kendileri böyle diyorlar, her şeyden önce, örneğin Etkili Java'da , bunun hakkında ayrıntılı olarak yazan Josh Bloch . Java API bugün geliştirildiyse, çok farklı görüneceğinden ve finaldaha büyük bir rol oynayacağından emin olabilirsiniz.
Konrad Rudolph

1
Hala 'final'i kullanmanın en iyi uygulama haline geldiğine ikna olmadım. Kanımca, 'final' sadece performans gereklilikleri gerektirdiğinde veya tutarlılığın alt sınıflar tarafından kırılamayacağından emin olmanız durumunda kullanılmalıdır. Diğer tüm durumlarda, gerekli dokümantasyon, dokümantasyona (yine de yazılması gereken) girmeli ve kaynak koduna değil, belirli kullanım modellerini zorlayan anahtar kelimeler olarak kullanılmalıdır. Bana göre bu bir tür tanrı oynuyor. Daha iyi bir çözüm olabilecek açıklamaları kullanmak. Bir 'final' ek açıklaması eklenebilir ve derleyici bir uyarı verebilir.
Jonny Dee,

8

Bir sınıfın alt sınıflarının olmadığı konusunda kendinize bir not bırakmak istiyorsanız, o zaman elbette bunu yapın ve bunun için bir yorum kullanın. "Final" anahtar sözcüğü bir yorum değildir ve yalnızca size bir şey bildirmek için dil anahtar kelimelerini kullanmak (ve yalnızca bunun ne anlama geldiğini biliyor olabilirsiniz) kötü bir fikirdir.


17
Bu tamamen yanlıştır! “Sadece bir şeyi işaret etmek için dil anahtar kelimelerini kullanmak […] kötü bir fikirdir.” - Aksine, tam olarak hangi dil anahtar kelimelerinin olduğu içindir. Geçici ihtarınız, “ve sadece ne anlama geldiğini bilen”, elbette doğrudur, ancak burada geçerli değildir; OP finalbeklendiği gibi kullanıyor . Bunda yanlış bir şey yok. Ve bir kısıtlamayı zorlamak için bir dil özelliğini kullanmak, yorum yapmaktan her zaman daha üstündür.
Konrad Rudolph

8
@Konrad: final"Bu sınıfın hiç bir alt sınıfı asla oluşturulmamalı" ("yasal sebeplerden dolayı veya başka bir şey için" hariç ), "bu sınıfın şu anda çocuğu yok, bu yüzden korunan üyeleriyle uğraşmak için hala güvenliyim" anlamına gelmiyor. Amacı final"serbestçe düzenlenebilir" çok antitezi olduğunu ve bir finalsınıf bile herhangi olmamalıdır protectedüyelerini!
SF.

3
@Konrad Rudolph Hiç minicik değil. Diğer insanlar daha sonra sınıflarını genişletmek isterse, "uzatılmamış" yazan bir yorum ile "uzayamayabilir" diyen bir anahtar kelime arasında büyük bir fark vardır.
Jeremy

2
@Konrad Rudolph OOP dil tasarımı hakkında bir soru sormak için harika bir fikir gibi geliyor. Fakat PHP'nin nasıl çalıştığını biliyoruz ve mühürlü olmadığı sürece uzantıya izin verme yaklaşımını kullanıyor. Anahtar sözcükleri birleştirmek için uygun olduğunu iddia etmek, çünkü "olması gerektiği gibi" sadece savunmasızlıktır.
Jeremy

3
@ Jeremy, anahtar kelimelerle uyuşmuyorum. Anahtar kelime final, “bu sınıf [şimdilik] genişletilmeyecek” anlamına gelir. Daha fazla değil, daha az değil. İster PHP Bu düşünceyle felsefesi ile dizayn edilmiştir alakasız şudur: varfinal sonuçta anahtar kelime. İkincisi, PHP'nin tasarımından savunarak, PHP'nin nasıl patchworky ve genel olarak kötü bir şekilde tasarlandığı göz önüne alındığında başarısızlığa uğramak zorundadır.
Konrad Rudolph

5

"Sınıflar ne zaman final ilan edilir" hakkında güzel bir yazı var . Ondan birkaç alıntı:

TL; DR: finalBir arayüz uygularlarsa sınıflarınızı her zaman yapın ve başka hiçbir ortak yöntem tanımlanmaz.

Neden kullanmak zorundayım final?

  1. Kıyamet devri miras zincirinin önlenmesi
  2. Cesaret verici kompozisyon
  3. Geliştiriciyi, kullanıcının genel API'si hakkında düşünmeye zorlayın
  4. Geliştiriciyi bir nesnenin genel API'sini daraltmaya zorla
  5. Bir finalsınıf her zaman genişletilebilir yapılabilir
  6. extends kapsülleme sonları
  7. Bu esnekliğe ihtiyacın yok
  8. Kodu değiştirmek için ücretsiz

Ne zaman kaçınmalı final:

Son sınıflar yalnızca aşağıdaki varsayımlar altında etkin bir şekilde çalışır:

  1. Son sınıfın uyguladığı bir soyutlama (arayüz) vardır.
  2. Son sınıfın genel API'sinin tamamı bu arayüzün bir parçasıdır

Bu iki ön koşuldan biri eksikse, kodunuz gerçekten soyutlamalara dayanmadığı için sınıfı genişletilebilir hale getireceğiniz bir noktaya ulaşacaksınız.

PS Harika okumalar için @ocramius'a teşekkürler!


5

Bir sınıf için "final" şu anlama gelir: Bir alt sınıf mı istiyorsunuz? Devam edin, "final" i, alt sınıfı istediğiniz kadar silin, ancak işe yaramazsa bana şikayet etmeyin. Kendi başınasın.

Bir sınıfın alt sınıflandırılabildiği zaman, başkalarının güvendiği davranış, alt sınıfların uyduğu soyut terimlerle tanımlanmalıdır. Değişkenlik beklemek için arayanlar yazılmalıdır. Belgeler dikkatlice yazılmalıdır; kaynak kodun henüz bulunmadığı için insanlara "kaynak koduna bakma" diyemezsiniz. Hepsi çaba. Bir sınıfın alt sınıf olmasını beklemiyorsam, bu gereksiz bir çaba. “final” açıkça bu çabanın yapılmadığını ve adil bir uyarı verdiğini söylüyor.


-1

Düşünmediğiniz bir şey, herhangi bir sınıfın değiştirilmesinin, yeni bir QA testine tabi tutulması gerektiği anlamına gelmesidir.

Gerçekten, gerçekten demek istemediğiniz sürece işleri nihai olarak işaretlemeyin.


Teşekkürler. Bunu daha fazla açıklayabilir misiniz? Eğer bir sınıfı final(bir değişiklik) olarak işaretlersem , tekrar denemek zorunda mıyım?
JW01

4
Bunu daha güçlü söyleyebilirim. Sınıfın tasarımından dolayı bir uzatma yapılamazsa, işleri nihai olarak işaretlemeyin.
S.Lott

Teşekkürler S.Lott - Final kullanımının kötü kullanımın kodu / projeyi nasıl etkilediğini anlamaya çalışıyorum. Eğer bir koruyucu kullanımı hakkında bu kadar dogmatik olmak neden olan herhangi bir kötü korku hikayeleri deneyimli mı final. Bu ilk elden deneyim mi?
JW01

1
@ JW01: Bir finalsınıfın bir tane birincil kullanım durumu vardır. Uzatmak istemediğiniz polimorfik sınıflarınız var çünkü bir alt sınıf polimorfizmi kırabilir. Alt sınıfların oluşturulmasını engellemediğinizfinal sürece kullanmayın . Bunun dışında, işe yaramaz.
S.Lott

@ JW01, bir üretim ayarında bir finali kaldırmak için İZİN YOK, çünkü bu müşterinin test ettiği ve onayladığı kod değil. Ancak, ekstra kod eklemenize izin verilebilir (test için) ancak sınıfınızı uzatamadığınız için istediğinizi yapamayabilirsiniz.

-1

'Final'i kullanmak, kodunuzu kullanmak isteyen başkalarının özgürlüğünü ortadan kaldırır.

Yazdığınız kod yalnızca sizin içinse ve hiç bir zaman halka veya bir müşteriye verilmeyecekse, kodunuzu istediğiniz şekilde yapabilirsiniz. Aksi takdirde, başkalarının kodunuza dayanmasını önlersiniz. Çok sık ihtiyaçlarım için genişletmek kolay olacak bir API ile çalışmak zorunda kaldım, ancak daha sonra 'final' tarafından engellendi.

Ayrıca, daha iyisi yapılmaması gereken bir kod var privateama protected. Elbette, private"kapsülleme" anlamına gelir ve uygulama ayrıntıları olarak kabul edilen şeyleri gizler. Ancak bir API programcısı olarak, yöntemin xyzuygulama detayı olarak kabul edildiğini ve dolayısıyla gelecekteki sürümde değiştirilebileceğini / silinebileceğini de belgeleyebilirim . Bu yüzden, uyarıya rağmen bu koda dayanacak olan herkes kendi riski altındadır. Ama aslında bunu yapabilir ve tekrar (umarım zaten test edilmiştir) kodunu kullanabilir ve bir çözümle daha hızlı ortaya çıkabilir.

Tabii ki, eğer API uygulaması açık kaynak ise, yalnızca 'final'i kaldırabilir veya yöntemleri' korumalı 'yapabilirsiniz, ancak kodu değiştirdiğinizden ve değişikliklerinizi yamalar şeklinde izlemeniz gerekir.

Bununla birlikte, uygulama kapalı bir kaynak ise, bir geçici çözüm bulma veya en kötü durumda, özelleştirme / uzatma olanakları ile ilgili daha az kısıtlama içeren başka bir API'ye geçerek geride kalırsınız.

'Nihai' ya da 'özel' bulmadığımı not edin, ancak programcının kodun yeniden kullanımı ve uzatılması açısından kodunu düşünmediği için sadece çok sık kullanıldığını düşünüyorum.


2
"Kalıtım kodun yeniden kullanımı değil".
quant_dev

2
Tamam, mükemmel bir tanım için ısrar edersen haklısın. Kalıtım, “bir-bir” ilişkisini ifade eder ve polimorfizme izin veren ve bir API'yi genişletmenin bir yolunu sağlayan bu gerçektir. Fakat pratikte kalıtım, kodu tekrar kullanmak için çok sık kullanılır. Bu özellikle çoklu kalıtımsal durumdur. Ve bir süper sınıfın kodunu çağırır çağırmaz, aslında kodu tekrar kullanıyorsun.
Jonny Dee

@quant_dev: OOP'de tekrar kullanılabilirlik, her şeyden önce polimorfinin anlamıdır. Ve kalıtım, polimorfik davranış için (arayüzü paylaşma) kritik bir noktadır.
Şahin,

@Falcon Paylaşım arayüzü! = Paylaşım kodu. En azından alışılmış anlamda değil.
quant_dev

3
@quant_dev: OOP anlamında tekrar kullanılabilirlik yanlış. Arayüz paylaşımı sayesinde tek bir yöntemin birçok veri tipinde çalışabileceği anlamına gelir. OOP kodunun yeniden kullanılmasının önemli bir parçası. Ve kalıtım otomatik olarak arayüzleri paylaşmamıza izin veriyor, böylece kodun yeniden kullanılabilirliğini büyük ölçüde arttırıyor. Bu yüzden OOP'ta tekrar kullanılabilirlik hakkında konuşuyoruz. Sadece rutinleri olan kütüphaneler oluşturmak neredeyse programlamanın kendisi kadar eski ve neredeyse her dilde yapılabilir, ortaktır. OOP'da Kod Yeniden Kullanımı bundan daha fazlasıdır.
Falcon,
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.