“Hafıza için korkunç” argümanı tamamen yanlıştır, ancak nesnel olarak “kötü bir uygulama” dır . Bir sınıftan miras aldığınızda, yalnızca ilgilendiğiniz alanları ve yöntemleri miras almazsınız. Bunun yerine her şeyi miras alırsınız . Sizin için yararlı olmasa bile, ilan ettiği her yöntem. Ve en önemlisi, ayrıca sınıfın sağladığı tüm sözleşmeleri ve garantileri devralırsınız.
SOLID kısaltması, iyi nesne yönelimli tasarım için bazı sezgiler sunar. Burada, ben nterface Ayrışma İlkesi (ISS) ve L iskov değişikliği Pricinple (LSP) bir şey söylemek.
ISS bize arayüzlerimizi mümkün olduğunca küçük tutmamızı söylüyor. Ancak miras alarak ArrayList
, birçok, çok yöntem alırsınız. O anlamlı mı get()
, remove()
, set()
(replace) veya add()
belirli bir dizinde (insert) bir alt düğümü? ensureCapacity()
Altta yatan listeye duyarlı mı ? sort()
Bir Düğüm için ne anlama geliyor ? Sınıfınızın kullanıcılarının gerçekten bir alması gerekiyor subList()
mu? İstemediğiniz yöntemleri gizleyemediğiniz için, tek çözüm ArrayList'i üye değişken olarak kullanmak ve gerçekte istediğiniz tüm yöntemleri iletmektir:
private final ArrayList<Node> children = new ArrayList();
public void add(Node child) { children.add(child); }
public Iterator<Node> iterator() { return children.iterator(); }
Dokümantasyonda gördüğünüz tüm yöntemleri gerçekten istiyorsanız, LSP'ye geçebiliriz. LSP bize alt sınıfı ana sınıfın beklendiği yerde kullanmamız gerektiğini söyler. Eğer bir fonksiyon bir ArrayList
parametre alırsa ve Node
bunun yerine geçersek, hiçbir şeyin değişmemesi gerekir.
Alt sınıfların uyumluluğu, tür imzaları gibi basit şeylerle başlar. Bir yöntemi geçersiz kıldığınızda, üst sınıfla yasal olan kullanımları dışlayabileceğinden, parametre türlerini daha katı yapamazsınız. Ancak bu, derleyicinin bizim için Java'da kontrol ettiği bir şeydir.
Fakat LSP çok daha derinlere iniyor: Tüm ebeveyn sınıflarının ve arayüzlerin dokümantasyonu ile vaat edilen her şeyle uyumluluğu korumak zorundayız. In verdikleri yanıta Lynn böyle bir durumda bulmuştur List
(eğer aracılığıyla miras arayüzü ArrayList
) garanti nasıl equals()
ve hashCode()
yöntemler işe gerekiyor. Çünkü hashCode()
tam olarak uygulanması gereken belirli bir algoritma bile veriliyor. Bunu yazdığınızı varsayalım Node
:
public class Node extends ArrayList<Node> {
public final int value;
public Node(int value, Node... children) {
this.value = Value;
for (Node child : children)
add(child);
}
...
}
Bunun için value
, buna katkıda bulunamama hashCode()
ve etkilemememiz gerekir equals()
. List
Ondan devralan tarafından onuruna söz - - arayüz gerektirir new Node(0).equals(new Node(123))
gerçek olamayacak kadar.
Sınıflardan miras almak, bir üst sınıfın verdiği bir sözü yanlışlıkla kırmayı çok kolaylaştırdığından ve genellikle amaçladığınızdan daha fazla yöntem ortaya koyduğundan, genellikle kalıtım yerine kompozisyonu tercih etmeniz önerilir . Bir şeyi miras almanız gerekiyorsa, yalnızca arabirimleri miras almanız önerilir. Belirli bir sınıfın davranışını tekrar kullanmak istiyorsanız, onu bir örnek değişkeninde ayrı bir nesne olarak tutabilirsiniz, böylece tüm sözleri ve gereksinimleri size zorlanmaz.
Bazen, doğal dilimiz miras ilişkisi önerir: Bir otomobil bir araçtır. Motosiklet bir araçtır. Sınıfları tanımlamalı mıyım Car
ve Motorcycle
bunu bir Vehicle
sınıftan miras almalı mıyım ? Nesneye yönelik tasarım, gerçek dünyayı tam olarak bizim kurallarımızda yansıtmakla ilgili değildir. Gerçek dünyanın zengin taksonomilerini kaynak kodumuzda kolayca kodlayamayız.
Böyle bir örnek, çalışan-patron modelleme problemidir. Person
Her birinin bir adı ve adresi olan çok sayıda s var . Bir Employee
bir olup Person
ve vardır Boss
. A Boss
da bir Person
. Öyleyse ve Person
tarafından miras alınan bir sınıf oluşturmalı mıyım? Şimdi bir sorunum var: patron aynı zamanda bir çalışan ve başka bir üstünlüğü var. Öyleyse , uzatılmalı gibi görünüyor . Ama bu bir değil mi? Herhangi bir kalıtım grafiği, bir şekilde burada bozulur.Boss
Employee
Boss
Employee
CompanyOwner
Boss
Employee
OOP, hiyerarşiler, miras ve mevcut sınıfların yeniden kullanımı ile ilgili değildir, davranışların genelleştirilmesiyle ilgilidir . OOP “Bir sürü nesnem var ve onların belirli bir şey yapmalarını istiyorum - ve nasıl umurumda değil” ile ilgili. Arayüzler bunun için. Eğer uygularsanız Iterable
şunlara ait arayüz Node
bunu iterable yapmak istiyorum, çünkü o iyi bir sonuçtur. Collection
Arabirimi, alt düğümleri eklemek / kaldırmak istediğiniz için uygularsanız, sorun değil. Fakat başka bir sınıftan miras almanızın nedeni, size, yukarıda belirtildiği gibi dikkatli bir düşünce vermediyseniz, ya da en azından olmayan her şeyi verir.