Interface’lerin Mantığı Nedir(2)? (Örnek Kullanımlar)

Mehmet Fatih Ercik
Codable
Published in
4 min readMay 17, 2019
Photo by Scott Webb on Unsplash

İlk makalede vurgulandığı gibi, bir çok kişi ,interface kavramını basit örnekler(Animal, Dog, Shape vb) üzerinden anlatabiliyor. Fakat interface’leri kullanma ve mantığını anlama konusuna gelince eksiklikleri ortaya çıkıyor.

Serinin bu makalesinde basit örnekler yerine, gerçek hayatta kullanılan kodlar üzerinden ilerlemenin daha faydalı olacağını düşündüm. Bunun için Java kaynak kodundan örnek vermeye karar verdim. JDK’da sıkılıkla kullanılan Comparable ve Comparator interface’lerini örnek olarak kullanacağım.

Başalamadan önce Serinin bir önceki makalesini özetlersek;

  • Interfacele’rin de tip(type) tanımlamak için kullanıldığını
  • Polimorfizm’in bir objenin bir den fazla tipte bulunması olduğunu
  • Interface’lerin farklı class’lar arasında ortak bir bağ kurmak için kullanıldığını
  • Casting yapan objenin(Polis veya Belediye Görevlisi) sadece cast edilen tipteki(SurucuEhliyeti, OgrenciKarti) metotlara erişebileceğini

anlatmaya çalışmıştım.

Bu makalede örnek olarak kullanacağımız Comparator, Comparable ve TreeMap interface ve class’larının

  • kullanım amaçların,
  • bunların bir biri ile olan ilişkilerini
  • Interface’larin kullanılmaması durumunda oluşacak kodun nasıl olacağını

anlatmaya çalışacağım.

Comparator ve Comparable Interface’leri

Comparator interface’i aynı tipteki iki objenin büyüklük, küçüklük ve eşitlik durumunu kontrol etmek için kullanılan bir interfacedir.
Comparator interfacinde bulunan compare metodu parametre aldığı iki objeden ilki, ikincisinden büyükse pozitif integer, küçükse negatif integer, eşitse sıfır return edecek şekilde tasarlanmıştır.

Birde benzer işi yapan Comparable interface’i var. Comparable interface’indeki compareTo metotu tek parametre alıp, yine duruma göre pozitif, negatif veya sıfır döner.

String class’ı Comparable interface’ini implement eder. String class’ındaki compareTo metodu alfabetik sıraya göre iki String objesini karşılaştırır.

Aynı şekilde aşağıda görüldüğü gibi, Integer ve Double class’ları da Comparable interface’ini implement eder. Buradaki sıralama küçükten büyüğe doğrudur.

Yine bir önceki yazıda geçecn Insan class’ıda, Comparable interface’ini implement edebilir. Yani insan kendisini başkası ile kıyaslayabilir. Aynı zamanda Insan farklı iki insanı da karşılaştırabilir. Bu durumda Comparator interface’ini implement etmesi gerekir.

Yukarıda görüldüğü gibi, bütün bu Comparable interface’ini implement eden class’lar compareTo metotunda parametre olarak kendi tipindeki objeleri alırlar. Yani Comparable interfacinin implementasyon olarak kattığı ekstra bir özellik yok. Bu durumda Comparable interface’ini kullanmadan compareTo metodu yazılamaz mı? Elbette yazılabilir. Gayette güzel çalışır. O zaman Comparable interface’ini kullanmak ne işimize yaradı?

Yukarıda bahsettiğim gibi interface’ler farklı class’lar arasında bir bağ kurmak için kullanılırlar. Eğer Comparable interface’ini kullanmamış olsaydık String, Integer, Double ve Insan class’larının bir birleri ile herhangi bir bağlantısı olmayacaktı. Hepsi tamamen bir birinden farklı alakasız sınıflar olacaktı. Bu oluşturduğumuz bağ ne işimize yarıyacak? Bu bağı nasıl kullanacağız?

TreeMap class’ını inceleyelim.

TreeMap Class’ı

Map’ler bilgileri key, value şeklinde saklayan bir data tipidir. Map’lerin, Java’da HashMap, LinkedHashMap, TreeMap vb gibi farklı implementasyonları bulunur. TreeMap bilgileri key değerine göre sıralı tutar.

Aşağıdaki örnekte görüldüğü gibi TreeMap’e farklı sıralamada data eklediğimizde TreeMap’in bunu kendi içerisinde sıralı tutuğunu görebiliriz. treeMap değişkenini consola yazdırdığımızda küçükten büyüye doğru sıralı bir şekilde yazdığını görürüz.

Yani kısaca TreeMap dataları key değerine göre sıralı tutar. Yukarıdaki örnekte key değerleri Integer’dır. Dolayısı ile sayıları doğal sıralama olan küçükten büyüğe doğru sıralar.

Key’leri sıralamak için bunları birbiri ile karşılaştırılması gerekir. Bu karşılaştırmayı Comparator veya Comparable interface’lerini kullanarak yapıyor.

TreeMap Comparable ve Comparator Interface’lerini nasıl kullanıyor?

Aşağıya TreeMap sınıfının konumuz ile alakalı kısımlarını kopyaladım. TreeMap karşılaştırma yaparken compare metodunu kullanıyor.

TreeMap Class’ı
Compare Metodu

Yukarıda TreeMap class’ının compare metotunda görüldüğü gibi eğer comparator alanı null ise, key’leri Comparable interface’ine cast eder. Daha sonra, compareTo metodunu kullanrak karşılaştırma yapar.

((Comparable<? super K>)k1).compareTo((K)k2)

Eğer comparator alanı null değil ise Comparator interface’inin compare metodunu kullanarak key’leri karşılaştırır.

comparator.compare((K)k1, (K)k2)

TreeMap class’ı, Comparable interface’ini kullanarak key’leri karşılaştırıyor. Bu karşılaştırmayı yaparken key’lerin Comparable tipinde olmasını bekliyor

(Comparable<? super K>)k1

Yani key’in class’ının String,Integer,Double veya Insan olmasına bakmıyor. Sadece Comparable tipine cast edilebiliyor mu edilemiyor mu buna bakıyor. Eğer Comparable tipine cast edemez ise ClassCastException fırlatıyor. Comparable interface’inin, String,Integer,Double ve Insan class’ları arasında oluşturduğu ortak bağı kullanıyor.

Interface’ler Olmasaydı

Peki şöyle bir senaryonun olduğunu düşünelim.

String,Integer, Doube class’ları Comparable interface’ini implement etmediğini fakat yinede aynı compareTo metoduna sahip olduğunu farzedelim.

Aşağıda, Comparable interface’lerinin silinmiş halini yazdım. Comparable silinmemiş hali, class tanımlarını hemen üstünde yorum satırına alınmış.

Comparable Silinmiş Integer,String ve Double Class’ları

Bunun yanında TreeMap class’ınında Comparable veya Compator class’larını kullanmadığını var sayalım.

TreeMap implementasyonu nasıl olabileceğine bakalım.(Reflection kullanmadan)

Olası TreeMap Implementasyonu

Yukarıda compare metotunda görüleceği üzere, kullanmak istediğimiz bütün class’lar için instanceof kullanarak objenin tipini kontrol etmemiz gerekecekti.

if(k1 instanceof Integer&&k2 instanceof Integer)if(k1 instanceof String&&k2 instanceof String)if(k1 instanceof Double&&k2 instanceof Double)

Tip kontrolünü yaptıktan sonra gerekli casting işlemini yapıp, daha sonra compareTo metodunu kullanacaktık.

(Integer)k1).compareTo((Integer)k2)
(String)k1).compareTo((String)k2)
(Double)k1).compareTo((Double)k2)

Ayrıca key olarak kullanmak istediğimiz her class için compare metodunda değişiklik yapmamız gerekecekti. Veya yeni bir alt class oluşturarak compare metodunu override etmemiz gerekecekti. Compare metodunun ne kadar karmaşık ve uzun olabileceğini hayal edebiliyor musunuz? Ayrıca SOLID prensiplerinden olan Open-Close prensibine aykırı bir kullanım olacaktı.

Allah’tan Interface’ler varda böylebir şeye gerek olmadı :)

Bu yazıda özetle;

  • Interface’lerin farklı class’lar arasında bağ kurmak için kullanıldığını
  • Interface’lerin oluşturduğu ortak bağın nasıl kullanılabileceğini

örnekler üzerinde anlatmaya çalıştım.

Bu yazı dizisinde interface’lerin tanımından başlayıp, gerçek hayattaki bir kullanım örneğine kadar basittien zora doğru anlatmaya çalıştım. Eksik gördüğünüz veya yanlış olduğunu düşündüğünüz bir nokta varsa lültfen bildiriniz.

--

--