emrah dayioglu java html css js android

Diamond problem

"Deadly Diamond of Death" de denilen yazılım mimarisinden kayaklanan "object oriented programming" ile ilgili bir problemdir. Mesela doğadaki canlilari ifade eden "Canlı" diye bir sınıfımız olsun. Bu "Canlı" sınıfının altında bundan kalıtım yoluyla türetilmiş "Kedı" ve "köpek" diye iki sınıfımız daha olsun. Örneğimizde "Canlı" sınıfına "yemekYe()" diye bir metod oluşturalım. "kedi" sınıfının kendine has yemek yeme özelliği vardır. Bu nedenle "Canlı" sınıfının "yemekye()" metodunu "override" yaparak kendine has yemek yeme metodunu oluşturuyoruz. ayni şekilde "köpek" sınıfının da kendine has yemek yeme özelliği vardır. Bunun için de "Canlı" sınıfının "yemekye()" metodunu "override" ediyoruz. buraya kadar her şey yolunda gidiyor. (Buraya kadar olan kısmı Abstract class veya interface konusuna girmeden daha sade anlatmaya calıştım, yoksa bu konuda daha iyi yapı oluşturulabilir elbette)







class Canli{
   public void yemekYe(){
     // her canlı gibi yemek ye
   }
}

class Kedi extends Canli{
   public void yemekYe(){
     // kedi gibi yemek ye
   }
}

class Kopek extends Canli{
   public void yemekYe(){
     // kopek gibi yemek ye
   }
}

Kedi kendisine has yemek yeme özelliğine sahip, köpek de kendisine has yemek yeme özelliğine sahip. bunun dışında tüm hayvanların da yemek yeme özelliği kalıtım yoluyla diğer hayvan türlerine aktarılmak üzere mevcut duruyor. Fakat ileride evde beslemek üzere "evhayvani" adında bir sınıf daha yaratırsak ne olur? elbette tüm hayvanlar ev hayvanı değildir o nedenle "evhayvani" sınıfını "Canlı" sınıfından değil de "kedi" ve "köpek" sınıflarından kalıtım yoluyla türetmemiz gerekecek. (Elbette ideal bir mimaride ev hayvanı bir interface olmalı ama ideal olmayan bir problemi ortaya koymak icin bu örneği verdim). Ev hayvani olan kedi doğada yasayan vahşi hemcinslerinden farklı yemek yeme davranışına sahip. Aynı şekilde köpek de. Şimdi bizim bu "evhayvanlari" iki sınıftan türetildi bunlar "kedi" ve "köpek", ikisi de "yemekye()" metoduna sahip. eğer ev hayvanımıza yemek ye dersek bu ev hayvani kedi gibi yemek ye metodunu mu çalıştıracak yoksa köpek gibi mi? bu bir cikmaz, "Canlı" sinifindan cikan iki dal "kedi" ve "köpek" diye ayrildi ama tekrar bu dallar "evhayvanlari" sinifinda birlesti, tipki bir baklava dilimi sekli gibi <> yada elmas (diamond) sekli gibi birlesti. bu durum özel olarak cözüm üretilmesi gereken bir problem.



class Canli{
   public void yemekYe(){
     // her canlı gibi yemek ye
   }
}

class Kedi extends Canli{
   public void yemekYe(){
     // kedi gibi yemek ye
   }
}

class Kopek extends Canli{
   public void yemekYe(){
     // kopek gibi yemek ye
   }
}
// aslında java da coklu kalıtım yanı multiple inharitance yoktur. 
// Burada olsaydı ne olurdu açıklamak için ekledim
class EvHayvani extends Kedi, Kopek{
   public static void main (String[] args){
     EvHayvani evHayvani = new EvHayvani();
     evHayvani.yemekYe(); // iste burada ne olacak, bu ev hayvani hem kedi hem de köpek, nasil yemek yiyecek ?
   }
}


İşte bu problemle karşılaşmamak için java dili iki ayrı sınıftan kalıtım almayı engellemiştir yani java dilinde "multiple inheritance" yoktur. Ideal yapı aşağıdaki gibi olmalıdır. Yani Canlı ismiyle bir abstract class olustururuz cünkü sadece canlı yoktur, canlı olan ya kedidir ya köpek, bu nedenle abstract. Ev hayvanı diye interface olustururuz cünkü ev hayvanı olmak kedi ve köpegin özelligidir, Kedi ve Köpegin kalıtımsal kökeni degildir. Diger yandan Canlı olmak kalıtımsak kökenidir. Kedi ve Köpek sınıfları da Canlı sınınının alt sınıfı yani kalıtımla almış ama EvHayvanı özelligini interface nedeni ile uygular.




abstract class Canli {
 void yemekYe(){
  System.out.println("Canli gibi yemek ye");
 }
}

interface EvHayvani{
 public void yemekYe();
}

class Kedi extends Canli implements EvHayvani {
 public void yemekYe(){
  System.out.println("Kedi gibi yemek ye");
 }
}

class Kopek extends Canli implements EvHayvani {
 public void yemekYe(){
  System.out.println("Kopek gibi yemek ye");
 }
}


Diamond problem yapısal olarak java dilinde gercekleştirilebilir degildi ta ki "java 8"'e kadar. java 8 de "interface"ler de "uygulanmış" metodlar barındırabilir. Elbette önceki örnekte dedigim gibi javada "extends" anahtar kelimesi ile sadece bir sınıftan inheritance yapabiliyoruz. Ama bu interface kullanımında böyle değildir, bir sınıf birçok "interface"'i "implements" anahtar kelimesi ile uygulayabilir. java 8 e kadar "interface"'ler metod barındırmadığı için bir mimari sözleşme veya yaptırım olarak görev almış fakat java 8 de "interface"'ler metod barındırabilmesi ile işlevsellik kazanmıştır. bu da "diamond problem" başka bir deyişle "deadly diamond of death" probleminin önünü açacak olmuş ama bu sefer de yapı değil compiler buna izin vermez.


Yukarıdaki herseyi bir kenara bırakıp bu sefer farklı bir örnekle farklı bir mantık kuralım. Bir insanımız var "Insan" sınıfı ile türetebileceginiz. Bu insan "ArabaSurebilir" interface ile araba sürme özelligi kazanıyor ve araba sürmenin bir olayı olarak ayak ile frene basabiliyor. Aynı insanımız bisiklet de sürebilir ve bu özelligi "BisikletSurebilir" interface ile alıyor ama bu sefer frene basma isini eli ile yapıyor.


interface ArabaSurebilir {
 default void freneBas(){
  System.out.println("Ayak ile frene bas");
 }
}

interface BisikletSurebilir {
 default void freneBas(){
  System.out.println("El ile frene bas");
 }
}

class Insan implements ArabaSurebilir, BisikletSurebilir{
 public static void main(String[] args){
  Insan insan = new Insan();
  insan.freneBas();
 }
}
Simdi biz bu adama frene bas demek istedik ama compiler buna izin vermez ve söyle bir hata fırlatır

C:\javaExample>javac Insan.java Insan.java:1: error: class Insan inherits unrelated defaults for freneBas() from types ArabaSurebilir and BisikletSurebilir class Insan implements ArabaSurebilir, BisikletSurebilir{ ^ 1 error 

Hata veriyor cünkü diyor ki sen bu adama "frene bas" diyorsun da bu adam hem araba hem bisiklet kullanabilen bi adam, simdi frene bas diyince bu adam bundan ne anlasın, el ile bisiklette gibi mi bassın, yoksa arabadaki gibi ayakla mi bassın. Olmaz "Deadly Diamond of Death" yarattın yapını düzelt diyor.