İçeriğe geç

Java 8 ile Ezber Bozan Interface Yapısı

Merhabalar,

Bugün ezberimizi bozan bir konudan bahsedeceğiz. “Interface”ler.

Java dilinde interface olarak adlandırdığımız arayüzler en kaba tabiri ile classların davranış imzalarını attığımız yapılardır. Örnek verecek olursak öğrenci dediğimiz zaman yapması beklenen iş olarak okula gelmesi, ders çalışması, sınava girmesini söyleyebiliriz. Bunun dışında öğrenci voleybol da oynayabilir. Ama biz kesin olarak yapması gerekenlerden olan okula gitmesi, ders çalışması gibi davranışları arayüzlerde imzalayarak kullandığımız somut bir Ogrenci classında bu arayüzdeki davranışları zorunlu olarak kullanmamız gerektiğini bildiririz. Ekip çalışmalarında her çalışma arkadaşımıza her öğrenci mutlaka ders çalışmalı dememimizin teknik yöntemidir diyebiliriz.

Gelelim asıl konumuz olan java 8 ile gelen interface yapısındaki değişikliklere.

En büyük değişiklik ve ezber bozan dediğimiz durumdan başlayalım. java 8’e kadar hep şu cümleyi kurduk: “interface içerisinde sadece metodun imzasını koyabiliriz. Ve bu imzayı interface’in kendisini implement eden bütün concreate class’lar kullanmak zorundadır.”   Ama java 8 ile beraber bu cümle geçerliliğini yitirdi. Artık interface içerisinde yazdığımız metotları sadece imza olarak bırakmak zorunda değiliz. Yani artık gövdeli metotları da interface’ler içerisinde tanımlayabiliriz ve bu metotları class implementasyonlarında direkt kullanabiliriz. Bunu yapmanın yolu ise hazırladığımız interface içerisindeki metodun access modifer’ının default veya static olmasıdır.

Bu yeni interface yapısı ile ilgili çeşitli case’ler üzerinde duracağız.Maddeler halinde bu yapıları inceleyelim:

*default ve static tanımlanan metotlarda şöyle bir güzellik oluşuyor. Bir interface’den implement olan onlarca class olabilir. Daha sonra projenin büyümesi ve değişen ihtiyaç yapısına göre bazı classların bu implement oldukları arayüzdeki bazı metotları  kullanmasını, bazı metotlarını kullanmamasını istemeyebilirsiniz. Bu durumda interface üzerine ekleyeceğiniz her imzayı bütün classlar kullanmak zorunda olacağı veya interface üzerinden kaldırdığınız her metodu classlar üzerinde ovverride edilmediğini tek tek belirtmek zorunda kalacaksınız. Tüm bunlar yerine default veya static tanımlanan metotlar implementasyon zorunluluğunu kaldırdığı için bu tür sorunlarla karşılaşmayacağız. 

Bu durumda çoklu kalıtımdaki sorun burada da karşımıza çıkmaz mı?

Evet arkadaşlar! Java bilindiği üzere çoklu kalıtımı desteklemez. Sebebi ise concreate classlardaki metotlar gövdeli olacağı için aynı metot imzasına sahip birden fazla classtan miras alan bir subclass’ın üst classlardan hangisinin metodunu kullanacağını kestiremiyor olmasıdır.

Diamond Problem olarak bilinen bu problemin önüne geçmek açısından java çoklu kalıtımı desteklemez. Ama çoklu implementasyonu destekler. Çünkü soyut sınıflardan aldığımız bu metotlar zaten gövdesizdir. Zaten siz override edip dolduracaksınız içerisini. Peki java 8 ile gelen interface’lere gövdeli metot yazabilme özelliği ile tekrar diamond problemle karşılaşmaz mıyız? Aşağıdaki örnekleri inceleyerek detaylara inelim.

public interface IHayvan {

default void beslenir(){
System.out.println("Hayvan Beslenir");

}

}
**************************************
public interface ICanli {

default void beslenir(){
System.out.println("Bitki Beslenir");
}
}
*****************************************
public class Kedi implements IHayvan, ICanli {

}

*******************************************

Yukarıdaki gibi ICanli ve IHayvan adında oluşturduğumuz interface’lere aynı default imzaya sahip iki adet gövdeli metot ekledik.
(DİKKAT: Aşağıda konuşacağımız durumlar default tanımlanan metotlar için geçerlidir. Static metotlar için ufak bir açıklama yeterli olacaktır.)
Kedi classı bu iki interface’i implement edebilir. Ancak iki implemntasyonun içerisinde de aynı imzaya sahip gövdeli metot olduğu için diomond problemi ile karşılaşmamak adına şu şekilde bir uyarı alacağız:”Java8interface.Kedi inherits unrelated default for beslenir() from types Java8interface.IHayvan and Java8interface.ICanli”

Yani zorunlu olarak beslenir() metodunun override etmenizi isteyecektir.
Şu şekilde olacaktır.

public class Kedi implements IHayvan, ICanli {

@Override
public void beslenir() {

}
}
Ama siz yeni bir metot içeriği yazmak istemiyorsunuz. Hayvan Interface’inde yazdığınız beslenir metodunu kullanmak istiyorsunuz. Default tanımlamam metotları aşağıdaki kod örneğindeki gibi çekebiliriz.

public class Kedi implements IHayvan, ICanli {

@Override
public void beslenir() {
IHayvan.super.beslenir();
}
}

Default metotlara nesne üzerinden erişim sağlanır. Static tanımlanan metotlar bildiğimiz java yapısına uygun olarak direkt class üzerinden çağrıldığı için yukarıdaki classlar içerisindeki metotların access modifier’ları static olsaydı eğer bu hatalarla karşılaşmayacaktık. Çünkü her türlü bu metotları class üzerinden çağırmamız gerekeceği için compile time hatası almayacağız.

 

* static olarak belirtilen metotlar implement edildiği classlarda ovveried edilemez.

public interface IHayvan {

static void beslenir(){
System.out.println("Hayvan Beslenir");

}

}
public class Kedi implements IHayvan {
@Override
public void beslenir() {
IHayvan.beslenir();

}
}

static olarak tanımlanan metodu yukarıdaki gibi override etmeye kalktığınızda hata alacaksınız. Zaten class üzerinden çağrılan ve static olması gereği bir kere değer verebilen metodu ezemezsiniz!!!

*Interface ile fonksiyonel arayüz
Java 8 ile beraber hayatımıza lambda ifadesi geldi. Aslında buton click metotlarında(listener) biraz aşinayız bu duruma ancak java8 ile baraber javayı daha fonksiyonelleştirmeye başladı bu ifadeler. Kendimize göre özelleştirebiliyoruz.
Bunu da yine interfaceler üzerinden yapıyoruz. Örneğin:

public interface IBitki {

default void fotosentezYap(){
System.out.println("Bitki Fotosentez yapar");
}

void sula();
}
Burada IBitki interface'inde gövdeli ve gövdesiz metotlar bulunmaktadır.
Bu interface'i aşağıdaki gibi kullanabilirim.

public class Orkide{

public Orkide(){
IBitki bitki = ()-> System.out.println("Orkide sulanıyor");
bitki.fotosentezYap();
}
}
Bu şekilde fonksiyonel bir kullanım yapabilirim.
DİKKAT: fonksiyonel arayüz tanımı için interface içerisinde sadece bir adet gövdesiz metot olmak zorundadır. Birden fazla gövdeli metot bulundurabilir.

Github hesabımdan örneklere ulaşabilirsiniz.

Bug'sız Günler :)

Tarih:Java

İlk Yorumu Siz Yapın

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir