Kalıtım ve metot ezme
Kalıtım (inheritance), bir sınıfın başka bir sınıfın davranışlarını ve arayüzünü temel alarak özelleşmesini sağlar. Güçlü bir araçtır; ancak yanlış kullanıldığında sıkı bağımlı ve kırılgan sınıf hiyerarşileri oluşturabilir. Bu hafta kalıtımı is-a ilişkisi üzerinden öğrenecek ve kompozisyon alternatifiyle karşılaştıracağız.
Bu hafta neleri yapabilmelisiniz?
- üst sınıf ve alt sınıf kavramlarını açıklayabilmeli,
class Child(Parent)sözdizimini kullanabilmeli,- miras alınan metodu çağırabilmeli,
- metot ezme (override) yapabilmeli,
super()ile üst sınıf davranışını genişletebilmeli,is-ailehas-aayrımını kullanarak kalıtımın uygunluğunu tartışabilmeli,- alt türün üst türün beklenen davranışını bozup bozmadığını sorgulayabilmeli,
- yanlış kalıtım örneğini fark edebilmelisiniz.
İlk kalıtım örneği
Developer, Employee sınıfından describe() davranışını miras alır.
Bu ilişki anlamlıysa şu cümle doğal okunmalıdır:
Bir Developer, Employee’dir. (
Developer is an Employee)
Ancak yalnızca bu cümlenin kulağa doğru gelmesi yeterli değildir. Daha güçlü ikinci soru şudur:
Bir
Employeebeklenen yerdeDeveloperkullanıldığında, üst sınıfın sözleşmesi bozulmadan program çalışmaya devam ediyor mu?
Alt sınıf, üst sınıfın beklenen davranışını anlamsızlaştırıyorsa hiyerarşi sözdizimsel olarak kurulabilse bile tasarım zayıftır.
Alt sınıfa yeni davranış eklemek
Alt sınıf üst sınıf davranışlarını alıp yeni davranış ekleyebilir.
Override: davranışı özelleştirmek
Alt sınıftaki send, üst sınıftaki aynı adlı metodu ezer (override).
Override yaparken yalnızca metot adının aynı olmasına değil, çağıranın beklediği davranış sözleşmesinin korunmasına da dikkat edin. Örneğin üst sınıfta send(message) bir string döndürüyorsa alt sınıfın aynı çağrıda bambaşka türde ve ilgisiz bir sonuç üretmesi ortak kullanımı zorlaştırabilir.

Employee sınıfından türeyen Developer sınıfının describe() metodunu yeniden tanımlayarak davranışı ezmesi.super() ile genişletmek
super().__init__(name), üst sınıfın başlangıç kurulumunu tekrar yazmak yerine yeniden kullanır.

super().__init__() ile üst sınıfın name alanını kurup alt sınıfta language alanını ekleme.Her tekrar kalıtım nedeni değildir
Şu düşünce tehlikelidir:
“İki sınıfta aynı metot var, hemen ortak üst sınıf yapalım.”
Kalıtım, yalnızca kod tekrarını azaltmak için değil, anlamsal alt tür ilişkisini ifade etmek için kullanılmalıdır.
Örneğin Car ve Driver nesnelerinin ikisinde de name niteliği olabilir; ama Driver is a Car anlamsızdır. Ortak alan bulunması kalıtım gerekçesi değildir.
is-a ve has-a
| İlişki | Örnek | Tipik araç |
|---|---|---|
| is-a | Developer bir Employee’dir |
kalıtım |
| has-a | Car bir Engine’e sahiptir |
kompozisyon |
Bir sınıf başka bir nesnenin davranışını kullanmak istiyor diye onun alt sınıfı olmak zorunda değildir.
Kırılgan hiyerarşi sezgisi
Derin kalıtım zincirleri:
Entity
└── Person
└── Employee
└── TechnicalEmployee
└── Developer
başlangıçta düzenli görünebilir; ancak üst sınıftaki küçük bir değişiklik birçok alt sınıfı etkileyebilir. Bu derste iki-üç seviyeden daha derin hiyerarşiler tasarlamayacağız.
OOP’nin hedefi mümkün olduğunca çok sınıf hiyerarşisi üretmek değildir. İyi tasarım bazen hiç kalıtım kullanmaz. Kompozisyonu her zaman gerçek bir alternatif olarak değerlendirin.
Alıştırma — Uygun ilişkiyi seç
Her çift için is-a, has-a veya “ikisi de değil” seçin:
Dog–AnimalOrder–CustomerLaptop–BatteryTeacher–CourseAdminUser–User
Kısa gerekçe yazın. is-a seçtiğiniz örneklerde ayrıca şu soruyu yanıtlayın: “Üst tür beklenen yerde alt tür güvenle kullanılabilir mi?”
Alıştırma — Override tamamla
return self.width * self.heightShape.area() içindeki NotImplementedError, burada “alt sınıf bu davranışı sağlamalı” beklentisini görünür kılan basit bir öğretim örneğidir. Bu kullanım sınıfı teknik olarak soyut yapmaz. Python’ın abc modülüyle tanımlanan gerçek soyut temel sınıf mekanizmasını gelecek hafta yalnızca kavram düzeyinde göreceğiz.
Alıştırma — super() ekle
Aşağıdaki alt sınıfta name niteliği kurulmamış:
Hata neden oluşur? AdminUser.__init__ içinde üst sınıf kurulumunu çağıracak tek satırı ekleyin.
Küçük üretim görevi — Ödeme türleri
Bir Payment üst sınıfı ve iki alt sınıf tasarlayın:
CardPaymentCashPayment
Her ikisi de pay(amount) davranışı sunsun; sonuç mesajları farklı olsun. Gerekirse alt sınıflara özgü nitelikler ekleyin.
Ardından şu soruyu cevaplayın:
Bu örnekte kalıtım gerçekten gerekli mi, yoksa aynı arayüzü sunan bağımsız sınıflar da yeterli olabilir mi?
Bu soru gelecek haftanın polimorfizm ve duck typing konusuna geçiştir.
Kendinizi kontrol edin
- Kalıtım hangi ilişkiyi ifade etmelidir?
is-acümlesine ek olarak hangi davranışsal soruyu sormak gerekir?- Override nedir?
super()ne sağlar?- Ortak kod bulunması tek başına kalıtım gerekçesi midir?
- Derin hiyerarşilerin bakım riski nedir?
Bu haftadan akılda kalması gerekenler
- Kalıtım bir
is-ailişkisidir; ancak alt türün üst türün sözleşmesini koruması da gerekir. - Alt sınıf davranışı miras alabilir, ekleyebilir veya override edebilir.
super()üst sınıf davranışını yeniden kullanmaya yardımcı olur.- Kalıtım, kod tekrarını azaltmanın evrensel çözümü değildir.
- Kompozisyon çoğu durumda daha gevşek ve esnek bağ kurar.