it-swarm.asia

Neden kaçının Java Kalıtım "Uzatır"

Jame Gosling dedi

“Mümkün olduğunca uygulama mirasından kaçınmalısınız.”

bunun yerine arayüz devralma özelliğini kullanın.

Ama neden? "Genişletme" anahtar sözcüğünü kullanarak bir nesnenin yapısını devralmayı nasıl önleyebilir ve aynı zamanda kodumuzu Nesne Odaklı hale getirebiliriz?

Birisi lütfen "bir kitapçıda kitap sipariş etme" gibi bir senaryoda bu konsepti gösteren Nesneye Dayalı bir örnek verebilir mi?

40
newbie

Gosling, extends anahtar kelimesinin kullanımından kaçınmayı söylemedi ... sadece mirasın kodun yeniden kullanılmasını sağlamak için bir araç olarak kullanılmadığını söyledi.

Kalıtım kendiliğinden kötü değildir ve OO yapılar oluştururken kullanmak için çok güçlü (temel) bir araçtır. Ancak düzgün kullanılmadığında (bir şey için kullanıldığında else Nesne yapıları oluşturmaktan çok), sıkı sıkıya bağlı ve bakımı çok zor olan bir kod oluşturur.

Polimorfik yapılar oluşturmak için kalıtım kullanılması gerektiğinden, arayüzler ile kolayca yapılabilir, bu nedenle nesne yapılarınızı tasarlarken sınıflar yerine arayüzleri kullanma ifadesi. Kendinizi uzantıları bir nesneden diğerine kopyalayıp yapıştırmadan kaçınmanın bir yolu olarak bulursanız, belki de yanlış kullanıyorsunuz ve bu işlevselliği işlemek ve bunun yerine kompozisyon aracılığıyla bu kodu paylaşmak için özel bir sınıfla daha iyi sunulur.

Liskov İkame Prensibi hakkında bilgi edinin ve anlayın. Bir sınıfı (veya bu konuyla ilgili bir arayüzü) genişletmek üzereyken, kendinize prensibi ihlal edip etmediğinizi sorun, evet ise, büyük olasılıkla doğal olmayan yollarla kalıtım kullanıyorsunuzdur. Yapması kolaydır ve çoğu zaman doğru gibi görünür, ancak kodunuzu korumak, test etmek ve geliştirmek zorlaşır.

--- Düzenle Bu cevap soruyu daha genel terimlerle cevaplamak için oldukça iyi bir argüman yapar.

38
Newtopian

Nesneye yönelik programlamanın ilk günlerinde uygulama mirası, kod yeniden kullanımının altın çekici kaynağıydı. Bir sınıfta ihtiyacınız olan bir işlevsellik parçası varsa, yapılacak şey o sınıftan herkese açık olarak miras almaktı (bunlar C++ 'ın Java'dan daha yaygın olduğu günlerdi) ve bu işlevi "ücretsiz olarak" aldınız.

Dışında, gerçekten özgür değildi. Sonuç, anlaşılması zor olan elmas şeklindeki kalıtım ağaçları da dahil olmak üzere, anlaşılması neredeyse imkansız olan son derece kıvrımlı miras hiyerarşileriydi. Bu, Java) tasarımcılarının sınıfların birden fazla mirasını desteklememeyi seçmesinin nedeninin bir parçasıdır.

Gosling'in tavsiyesi (ve diğer ifadeler) bunun gibi oldukça ciddi bir hastalık için güçlü bir ilaçtı ve bazı bebeklerin banyo suyuyla atılması olası. Sınıflar arasında gerçekten is-a Olan bir ilişkiyi modellemek için kalıtım kullanmanın yanlış bir yanı yoktur. Ancak sadece başka bir sınıftan bir işlev parçası kullanmak istiyorsanız, önce diğer seçenekleri araştırmaktan daha iyi olacaksınız.

9
JohnMcG

Miras son zamanlarda oldukça korkunç bir üne kavuştu. Bundan kaçınmanın bir nedeni, temelde insanları gerçek bir ilişki olmadığı kalıtım kullanmamaya, sadece kod yazmayı kurtarmak için teşvik eden "kalıtım üzerinde kompozisyon" tasarım ilkesi ile birlikte gider. Bu tür kalıtım, bazı zor bulmak ve düzeltmek zor neden olabilir. Arkadaşınızın muhtemelen bir arayüz kullanmayı önermesinin nedeni, arayüzlerin dağıtılmış api'lere daha esnek ve sürdürülebilir bir çözüm sağlamasıdır. Kullanıcı kodunu kırmadan bir API'de değişiklik yapılmasına daha sık izin verir, burada sınıfları açığa çıkarmak genellikle kullanıcının kodunu kırır. Bunun .Net'teki en iyi örneği Liste ve IList arasındaki kullanım farkıdır.

6
Morgan Herlocker

Çünkü sadece bir sınıfı genişletebilir, birçok arayüzü uygulayabilirsiniz.

Bir zamanlar kalıtımın ne olduğunuzu tanımladığını duydum, ancak arayüzler oynayabileceğiniz bir rol tanımlar.

Arayüzler ayrıca polimorfizmin daha iyi kullanılmasına izin verir.

Bunun sebebi olabilir.

5
Mahmoud Hossam

Bana da öğretildi ve mümkünse arayüzleri tercih ediyorum (elbette hala mantıklı olan miras kullanıyorum).

Sanırım yaptığı bir şey, kodunuzu belirli uygulamalardan ayırmaktır. Diyelim ki ConsoleWriter adında bir sınıfım var ve bir şeyler yazmak için bir yönteme geçiyor ve bunu konsola yazıyor. Şimdi bir GUI penceresine yazdırmaya geçmek istediğimi varsayalım. Şimdi ya yöntemi değiştirmek veya GUIWriter bir parametre olarak almak yeni bir tane yazmak zorunda. Eğer bir IWriter arabirimi tanımlayarak başlamış ve yöntem bir IWriter almak olsaydı ben ConsoleWriter (IWriter arabirimini uygular) ile başlayabilir ve daha sonra GUIWriter (aynı zamanda IWriter arabirimini uygular) adlı yeni bir sınıf yazmak ve sonra ben sadece geçmekte olan sınıfı değiştirmek zorunda kalacaksınız.

Başka bir şey (C # için doğru, Java hakkında emin değilim) sadece 1 sınıfı genişletebilir, ancak birçok arabirimi uygulayabilirsiniz. Diyelim ki Öğretmen, MathTeacher ve HistoryTeacher adında bir sınıfım var. Şimdi MathTeacher ve HistoryTeacher Öğretmen'den genişliyor, ancak hem MathTeacher hem de HistoryTeacher olan birini temsil eden bir sınıf istiyorsak. Bir seferde yalnızca bir tane yapabildiğinizde birden fazla sınıftan miras almaya çalıştığınızda oldukça dağınık olabilir (yol vardır, ancak tam olarak optimal değildir). Arabirimlerle IMathTeacher ve IHistoryTeacher adında 2 arabirime sahip olabilirsiniz ve daha sonra Öğretmen'den genişleyen ve bu 2 arabirimi uygulayan bir sınıfa sahip olabilirsiniz.

Arabirim kullanımıyla bazen insanların kodları yinelediğini görmemizin bir dezavantajı (her bir sınıf için arabirimi uygulamak için uygulama oluşturmanız gerektiğinden) ancak bu sorunun temiz bir çözümü var, örneğin delegeler gibi şeylerin (emin değilim) Java buna eşdeğerdir).

Arabirimleri miraslar üzerinde kullanmanın en büyük nedeni uygulama kodunun ayrıştırılmasıdır, ancak kalıtımın hala çok yararlı olduğu için kötülük olduğunu düşünmeyin.

1
ryanzec

Bir sınıftan miras alırsanız, yalnızca o sınıfa bağımlı olmazsınız, aynı zamanda o sınıfın müşterileri tarafından yaratılan örtülü sözleşmeleri de onurlandırmanız gerekir. Bob Amca, Liskov İkame Prensibi temel Kare Dikdörtgeni uzatır ikilemi kullanarak incelikli bir şekilde ihlal etmenin kolay bir örneğidir. Arabirimleri, hiçbir uygulamaları olmadığı için gizli sözleşmeleri de yoktur.

0
Michael Brown