23
Nis'14

OOP 10: Interface Kavramı (C# ile OOP)

Bundan önceki yazımda abstract sınıflardan bahsetmiştim. Şimdi ise abstract sınıfların yakından akrabası olan interfacelerden bahsetmeye çalışacağım. Okuldan mezun olduğumda iş görüşmelerinde karşıma sıkça şu soru çıktı: “Abstract class nedir? Interface nedir? Bu ikisi arasındaki farklar ya da benzerlikler nelerdir?” Bu sorunun ardından biraz boğazımı hafif öksürüklerle konuşmaya hazır hale getirdikten sonra “bildiğim kadarıyla” açıklamaya çalıştım hep. Gelin şimdi o zamanlar bildiğim kadarından biraz daha ileriye gidelim ve boğazımızı ufak öksürüklerle temizleyerek zaman kazanmak yerine, nedir ne değildir anlatalım anlayalım.

 

Interface kelime manası olarak arayüz demektir. Bir arayüzden beklentilerimiz, tabiri caizse asıl yüzeye bir referans sağlamasıdır. Burada asıl yüzeyi class olarak düşünebiliriz. Bir classın bu arayüzü yardımıyla biz o classın yetkinliklerinden kesin olarak haberdar olabilmekteyiz. Nasıl mı? Kural basit. Eğer bir class bir interface tarafından extend edilmiş ise o interface’in zorunlu kıldığı yetkinliklere de sahip olmuş demektir. Mesela foreach ile elemanları arasında bir döngü yapabildiğimiz tüm tipler, IEnumerable interface’inden extend edilmiş olmak zorundalardır. Şimdi daha fazla buraları kurcalamaya gerek yok. Sadece interface isimlendirmesinin “I” ile başladığına dikkat edin. Bu zorunlu olmasa da anlaşılabilirlik açısından güzel bir ayrıntıdır ve interfaceler için genel isimlendirme bu şekildedir.

 

Birkaç kural daha:

– Interfaceler, metod, property, event ve indeksleyiciler barındırabilirler.

– Sadece bir arayüz olduklarından da anlayabileceğimiz gibi, interfaceler elemanlarının gövdelerini barındırmazlar. Sadece tanımları vardır.

– Bir sınıf bir interface tarafından extend edildiğinde o interface’in tüm kurallarına uymak zorundadır. Yani tüm elemanlarını implemente etmek zorundadır.

– Sınıflarda olduğu gibi interfaceler için de tüm erişim belirleyicileri kullanabiliriz.

– Fakat interface elemanları için default erişim belirleyici public’tir. Kendimiz belirlemek istesek de derleyici hata verecektir.

 

Syntax aşağıdaki gibidir:

interface IOrnekInterface
{
    // Metod
    void OrnekMetod();
    // Property
    int OrnekPropery { get; set; }
    // Event
    event EventHandler OrnekEvent;
    // Indexer
    string this[int index]{ get; set; }
}

Event ve indexer hakkında şimdiye kadar bir açıklama yapmadığımdan bu konuda bunlara değinmeyeceğim.

Bir sınıf interface ya da interfaceler tarafından extend edildiğinde ise syntax aşağıdaki gibi olacaktır.

class OrnekClass : IOrnekInterface
{ 

}

Ama bir saniye! Burada yanlış giden bir şeyler olmalı. Hani sınıf bir interface tarafından extend edildiğinde tüm elemanları implemente etmek zorundaydı? Yukarıdaki gibi bir durum için derleyici bizi nazikçe uyaracaktır.

interface elemanlarını implemente zorunlu

Artık interface elemanlarını implemente etmenin yazılımcı için bir zorunluluk olduğunu görmüş olduk. Bir oop tasarımcısı böylelikle, interfaceler tanımlayarak ve bazı classları bundan extend ederek yazılımcıyı istediği metod, property, event ve indexleri kullanmaya zorlayabilir. Bir bütünlük sağlamak açısından da önemlidir.

 

Şu an kalabalık yapmaması açısından IOrnekInterface içerisindeki event ve index tanımını kaldırıyorum. Bu düzenlemeden sonra OrnekClass, IOrnekInterface elemanlarını implemente edince ilk görüntü aşağıdaki gibi olacktır. (Class ismi yanına iki noktadan sorna yazdığımız interface tanımı üzerine gelerek Ctrl + . kombinasyonundan sonra entera basabilirsiniz.)

class OrnekClass : IOrnekInterface
{
    public void OrnekMetod()
    {
        throw new NotImplementedException();
    }

    public int OrnekPropery
    {
        get
        {
            throw new NotImplementedException();
        }
        set
        {
            throw new NotImplementedException();
        }
    }
}

Ctrl + . ve enter kombinasyonundan sonra class içerisinin otomatik dolduğunu görebilirsiniz. Şu anda metod ve index içleri halen boş ve kodlamanızı bekliyor. Bir ayrıntı dikkatinizi çekmiştir. Henüz daha bir kodlama yapmadığımızda, Ctrl + . ve enter kombinasyonuyla otomatik gelen metod ve index, kullanılmaya çalışıldığında NotImplementedException verecek şekilde gelmiştir. Bunlar önemli ayrıntılardır. Bu hata fırlatılmayıp metod ve index içleri bomboş bırakılsaydı belki de bu classı kullanan yazılımcı hatanın nerede olduğunu anlamak için çok zaman kaybedecekti.

 

Artık main içerisinde şöyle güzel bir tanım ile bir kullanım gerçekleştirebiliriz.

static void Main(string[] args)
{
    IOrnekInterface ornekClass = new OrnekClass();
    ornekClass.OrnekMetod();
}

OrnekClass, IOrnekInterface tarafından extend edildiğinden böyle bir tanım yapabildik ve artık IOrnekInterface’in zorunlu kıldığı elemanları kullanabilir durumdayız. Tabiki ornekClass nesnesi OrnekClass tipinde olsaydı da OrnekMetod() ‘u kullanabiliyor olacaktık. Fakat bazen nesnenin tipini interface üzerinden vermek kurtarıcı olabilir. Mesela bir metoda parametre alırken alınan parametrenin hangi tipten olduğu bizim için çokta önemli olmayabilir. Örneğin sadece IEnumerable olması işimizi görebilecekse metoda alınacak parametreyi de IEnumarable tipinden tanımlyabiliriz.

 

Her şey çok güzel ama bunları abstract class ile de yapabilirim mi diyorsunuz?

 

Eğer böyle diyorsanız gerçekten haklısınız. O zaman bunları abstract class ile de nasıl yapabiliriz bir bakalım.

 

Interface’in tüm elemanları extend edilmek zorundaydı. <-> Abstract classın tüm elemanlarını virtual tanımlarız.

Interface elemanlarının gövdeleri interface içerisinde kodlanmazdı. <-> Abstract virtual elemanları da öyle.

 

Böyle bakıldığında abstract ve interfaceden biri gereksiz gibi görülebilir. Fakat c# ‘ta bir sınıf, tek bir sınıfı inherit edebilirken, birçok interface tarafından extend edilebilmektedir. Artık böyle bir ihtiyacın olup olmamasına göre interface ya da abstract class kullanmak yazılımcıya kalmıştır. İçerisinde hem virtual elemanlar hem de miras alınabilecek diğer elemanlara sahip bir base classa ihtiyacınız varsa abstract class kullanmanızı önerebilirim.

 

OrnekClass’ın hem IOrnekInterface hem de IEnumarable tarafından extend edilmiş hali aşağıdaki gibidir.

class OrnekClass : IOrnekInterface, IEnumerable
{
    public void OrnekMetod()
    {
        throw new NotImplementedException();
    }

    public int OrnekPropery
    {
        get
        {
            throw new NotImplementedException();
        }
        set
        {
            throw new NotImplementedException();
        }
    }

    public IEnumerator GetEnumerator()
    {
        throw new NotImplementedException();
    }
}

Böyle bir ihtiyaca doğadan örnek vermeye çalışayım. Uçabilen ve yürüyebilen canlılar için iki farklı class yapmış olalım(UcanCanlilar ve YuruyenCanlilar). Bir de tavuk classı olduğunu varsayarsak mantıken bu classın hem UcanCanlilar classını hem de YuruyenCanlilar classını inherit etmesi lazım. Fakat bunun mümkün olmadığını artık biliyoruz. Oysa uçan ve/veya yürüyen canlılar için class yapmak yerine interface tanımlamış olsaydık(IUcabilen, IYuruyebilen)  tavuk classını bu iki interfaceden extend edebilirdik. Artık tavuğumuz hem uçabiliyor hem yürüyebiliyor :)

 

Çıkmadan önce:

 

– Eğer bir class bir interface tarafından extend edilmiş ise o interface’in zorunlu kıldığı yetkinliklere de sahip olmuş demektir.

– C# ‘ta bir sınıf, tek bir sınıfı inherit edebilirken, birçok interface tarafından extend edilebilmektedir.

 

İyi Eğlenceler:)

Yeni makaleleri E-Mail ile takip edin!