ÖNEMLİ : Kendim için aldığım notlar. Umarım size de bir faydası olur. Kullanılan her bir makale referans olarak eklenmiştir.

Java’da Kalıtım(inheritance) ve Java’da Polimorfizm Serisi


  1. Java’da Kalıtım 1 - Kalıtımı Neden Kullanırız? Kalıtımı Sağlamak İçin Asgari Şartlar Nelerdir?
  2. Java’da Kalıtım 2- Extends
  3. Java’da Kalıtım 3 - Referans ve Nesne Tipleri
  4. Java’da Kalıtım 3.1 - Static ve Dinamik Tür
  5. Java’da Kalıtım 4 - Görünürlük/Erişim Değiştiricileri
  6. Java’da Kalıtım 5 - Java’da Nesne Oluşturma
  7. Java’da Kalıtım 6 - Sınıf İnşası için Derleyici Kuralları
  8. Java’da Kalıtım 7 - Sınıf Hiyerarşisinde Değişken İlklendirme
  9. Java’da Kalıtım 8 - Alıştırmalar
  10. Java’da Kalıtım 9 - Overriding(Ezici) Metotlar
  11. Java’da Kalıtım 10 - Overloading(Aşırı Yükleme) Metotlar

Kalıtımı Neden Kullanırız?

Kalıtım(inheritance) ve polimorfizm, nesneye dayalı bir programlama dilinde inanılmaz derecede güçlü özelliklerdir. Loop ve conditional‘ların aksine, kodunuzun çalışması için genellikle kalıtım ve polimorfizm kullanmanız gerekmez. Yani önemini, sahip olduğunuz kod devasa bir hale gelmeden anlayamazsınız. Çünkü kodunuz büyüdükçe yöntemleri ve daha sonra sınıfları kullanmaya başlarsınız. Aynı şekilde, projenizin karmaşıklığı arttıkça ve büyük yazılım tasarım projeleri üzerinde çalışmaya başladığınızda, projenin karmaşıklığını kaldırabilmek için kalıtım ve polimorfizm kullanmaya başlarsınız.

Java’da Kalıtım Kullanmadan Oluşturulan Örnek Kodlar

Bir örnekle konuya girmek istiyorum. Diyelim ki elimizde bir Person(kişi) sınıfı var. Ancak yazılım tasarım ekibiniz size, artık bir sınıfın yetmediğini, öğrenci ve öğretim üyeleri olmak üzere 2 farklı sınıfa daha ihtiyacın olduğunu söylüyor.

1
2
3
4
public class Person {
  private String name;
  ....
}


Varolan Person sınıfının üstüne bir de Student ve Faculty isminde iki sınıf daha oluşturmamız isteniyor. Peki ne yapmamız gerekiyor? Bu sorunu ele almak için ilk olarak 2 tane kötü çözüm yöntemi sunmak istiyorum. İlk olarak bu ihtimalleri görmeniz kalıtımın önemini anlamak açısından daha yerinde olacaktır.

Birinci Önerilmeyen Yöntem

İlk çözüm, olan biteni sadece Person sınıfında tutmaya çalışmak olsun. Yani demek istediğim aşağıdaki gibi bir kod;

Birinci kötü çözüm:


1
2
3
4
5
6
7
8
9
public class Person {
  private String name;
  private boolean student;

  public Person(boolean s){
    this.student = s;
  }
  ....
}
1
2
3
4
5
6
if (student){
  //code for students
}else{
  //code for faculty members
}
  ....

Yukarıda görüldüğü gibi karşılaştığım sorunları yine Person sınıfı içinde bir if-else conditional’ı kullanarak halledebilirim. Her seferinde bu kişi bir öğrenci mi? yoksa bir fakülte üyesi mi? şeklinde bir soru sormam yeterli olacaktır. Buradaki örnek basit gibi gözükse de, üye değişkenleri fazlalaştığında, bu durum içinden çıkılamayacak bir hâl alacaktır.

Fakat farklı öğrencilerin farklı davranışları da olabilir. Aynı durum fakülte üyeleri için de geçerlidir. Okulda mezun öğrenciler olduğu gibi, henüz mezun olmamış öğrenciler de olabilir. Her seferinde if-else kullanarak bu sorunu çözemeyiz.

Birinci kötü çözümün devamı:


1
2
3
4
5
6
7
8
9
10
11
public class Person {
  private String name;
  private boolean student;
  private boolean graduate;
  private boolean undergraduate;

  public Person(boolean s){
    this.student = s;
  }
  ....
}
1
2
3
4
5
6
7
8
9
10
11
if (student){
  if(graduate){
    //...
  }else if(undergraduate){
    //....
  }
  //code for students
}else{
  //code for faculty members
}
  ....

Bu tarz kodlamaya spagetti kodlama da denir.

İkinci Önerilmeyen Yöntem

Peki diğer kötü çözüm yöntemimiz nedir? Bu da, Person sınıfının Student ve Faculty isminde 2 farklı kopyasını oluşturmak olabilir. Yani Person sınıfının içeriğini doğrudan kopyalayıp bu yeni sınıflara yapıştırmaktan bahsediyorum;

İkinci kötü çözüm:


1
2
3
4
public class Student {
  private String name;
  ....
}
1
2
3
4
public class Faculty {
  private String name;
  ....
}

Peki buradan ne gibi problemler çıkardı? Cevabınız, tutarlılıkla(consistency) veya veri yapısının dağınıklığı ile ilgiliyse, doğru yoldasınız demektir. Şimdi her ikisini de konuşalım istiyorum.

Buradaki problem aslında tam olarak şudur. Örneğin Person sınıfının kodunda değişiklik yapmak istediğinizde, bu değişiklikleri Student ve Faculty sınıflarına da uygulamamız gerekecektir. Peki bunu her seferinde kopyala-yapıştır şeklinde mi yapacağız? Şayet böyle yaparsak ortak kodu tutarlı tutmak gerçekten zor olacaktır.

Veyahut Person[] tipinde bir dizi oluşturmak istediğimizi varsayalım. Bu dizinin öğrenci mi yoksa fakülte üyesi mi olduğuna nasıl karar vereceğiz? Veyahut bunu, sadece öğrenciler ve sadece fakülte üyeleri şeklinde iki farklı diziye ayırırsak ne olur? Student[] ve Faculty[] …. O zaman da kişileri temsil eden diziyi bir daha asla kullanamayız! Sonuç olarak öğrenciler ve fakülte üyeleri için iki farklı dizi tutmam gerekecek.

Tüm insanlar için tek bir veri yapısı tutmanın bir yolu olmadığını da görüyorum. Peki bu neden önemlidir? Yani sadece Person şeklinde tutmanın ne önemi olacak? Belkide amacımız, okuldaki insanları, öğrenci veya öğretim görevlisi ayrımı yapmadan, tek bir çatı altında kayıt altına almak olabilirdi. Yalnız bu durumda bunu yapmak gerçekten zor olurdu. Öğrencileri potansiyel olarak sıralayabilirim, öğretim görevlilerini de sıralayabilirim, ama bunları nasıl birleştirebilirim? Esasen, bu iki örneğe bakarak ne yapmamız gerektiğini az çok anladık.

Kodda tutarlılığı sağlamak ve veri yapısını tek bir sınıfta toplamak

Buradaki hedefler,

  1. Bütün ortak davranışları bir sınıfta tutmak,
  2. Farklı davranışa sahip olanları ise farklı sınıflara ayırmak
  3. Tüm bu nesneleri tek bir veri yapısında tutmak.

İşin güzel yanı bütün bunları kalıtım(inheritance) ile yapabiliriz. Sonraki yazımda bu hedeflerden ilk ikisini ele aldım, dilerseniz bakabilirsiniz.

Referanslar