Bu, siz kazmaya başlayana ve bunun aslında kötü bir fikir olduğunu anlayana kadar "açıkça iyi bir fikir" gibi görünen dil tasarım sorunlarından bir diğeri.
Bu postanın konu hakkında (ve diğer konularda da) çok şey var. Bizi mevcut tasarıma getirmek için bir araya gelen birkaç tasarım gücü vardı:
- Kalıtım modelini basit tutma arzusu;
- Açık örneklerin ötesine baktığınızda (örneğin,
AbstractListbir arayüze dönüştüğünüzde), equals / hashCode / toString'in kalıtımsal olarak alınmasının tekli mirasa ve duruma güçlü bir şekilde bağlı olduğunu ve arayüzlerin çok sayıda miras alınmış ve durumsuz olduğunu fark edersiniz;
- Potansiyel olarak bazı şaşırtıcı davranışların kapısını açtı.
"Basit tutma" hedefine zaten dokundunuz; kalıtım ve çatışma çözme kuralları çok basit olacak şekilde tasarlanmıştır (sınıflar arabirimleri kazanır, türetilmiş arabirimler süper arabirimleri kazanır ve diğer tüm çatışmalar uygulayıcı sınıf tarafından çözülür.) Elbette bu kurallar bir istisna yapmak için değiştirilebilir, ancak Sanırım o dizgiyi çekmeye başladığınızda, artan karmaşıklığın düşündüğünüz kadar küçük olmadığını göreceksiniz.
Elbette, daha fazla karmaşıklığı haklı çıkaracak bir dereceye kadar fayda var, ancak bu durumda orada değil. Burada bahsettiğimiz yöntemler eşittir, hashCode ve toString'dir. Bu yöntemlerin tümü özünde nesne durumu ile ilgilidir ve o sınıf için eşitliğin ne anlama geldiğini belirlemek için en iyi konumda olan arabirim değil, duruma sahip olan sınıftır (özellikle eşitlik sözleşmesi oldukça güçlü olduğu için; bkz.Etkili Bazı şaşırtıcı sonuçlar için Java); arayüz yazarları çok uzak.
AbstractListÖrneği çıkarmak kolaydır ; Bu AbstractListdavranıştan kurtulup Listarayüze koyabilirsek çok güzel olurdu . Ancak bu bariz örneğin ötesine geçtiğinizde, bulunabilecek pek çok iyi örnek yoktur. Kökte, AbstractListtek kalıtım için tasarlanmıştır. Ancak arayüzler çoklu kalıtım için tasarlanmalıdır.
Dahası, bu dersi yazdığınızı hayal edin:
class Foo implements com.libraryA.Bar, com.libraryB.Moo {
// Implementation of Foo, that does NOT override equals
}
FooSupertypes de yazar görünüyor, eşittir hiçbir uygulanmasını görür ve bunu elde etmek için referans eşitliği sonlandırıyor yapması gereken tüm devralır, eşit; Object. Daha sonra, gelecek hafta, Bar için kütüphane bakıcısı "yardımcı bir şekilde" varsayılan bir equalsuygulama ekler . Posta ile gönder Şimdi, Foobaşka bir bakım etki alanındaki bir arabirim tarafından anlamsallığı bozuldu ve ortak bir yöntem için bir varsayılan ekleyerek "yardımcı" oldu.
Varsayılanların varsayılan olması beklenir. Hiçbirinin olmadığı bir arabirime (hiyerarşinin herhangi bir yerinde) bir varsayılan eklemek, somut uygulama sınıflarının anlamlarını etkilememelidir. Ancak varsayılanlar Nesne yöntemlerini "geçersiz kılabilir", bu doğru olmaz.
Dolayısıyla, zararsız bir özellik gibi görünse de, aslında oldukça zararlıdır: Küçük artımlı ifadeler için çok fazla karmaşıklık ekler ve iyi niyetli, zararsız görünen değişikliklerin ayrı derlenmiş arabirimlere zarar vermesini çok kolaylaştırır. sınıfları uygulamanın amaçlanan semantiği.