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,
AbstractList
bir 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 AbstractList
davranıştan kurtulup List
arayüze koyabilirsek çok güzel olurdu . Ancak bu bariz örneğin ötesine geçtiğinizde, bulunabilecek pek çok iyi örnek yoktur. Kökte, AbstractList
tek 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
}
Foo
Supertypes 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 equals
uygulama ekler . Posta ile gönder Şimdi, Foo
baş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.