hayal et, tasarla, hayata geçir



Sınıf ve Kütüphane Tasarımları – Interface

Projelerimizin geliştirilmeye daha müsait ve daha modüler olabilmesi için uygulama altyapısının doğru bir şekilde tasarlanması gerekir. Ayrıca kod okunabilirliğini arttırmak ve diğer geliştiricilerle daha düzgün bir iletişim kurabilmek için yazdığımız projenin belli standartlara ve normlara uyması projenin akıbeti açısından önemlidir. Bu yazı dizimizde sınıf ve kod kütüphanelerimizi nasıl tasarlamamız gerektiği üzerinde durup projeleremizde yazdığımız kodları nasıl daha efektif kullanabileceğimizin üzerinde duracağız. Kaynak olarak çok faydalandığım Framework Design Guidelines kitabını ise herkese tavsiye ederim.

Interface Nedir?

Interface ile ilgili detaylı bir makale için buraya tıklayabilirsiniz. Fakat biz genede özet bir giriş yapalım.

Bir objenin yaşam çizgisini aslında şu şekilde özetleyebiliriz;
Interface > Abstract Class > Class > Sealed Class
Arayüzler (Interface) bu döngüde ilk sıralamayı almakta olup sınıf tasarımında en temel yapı olmaktadırlar ve bu sebepten ötürü ilk önce kurgulanmaları gerekir. Arayüzler aşağıdaki özellikleri barındırırlar;

  • - Bir sınıfın bulundurması gereken en temel property ve metodları içerirler.
  • - Tüm elemanları public olmak zorundadırlar.
  • - Hiç bir elemanı static veya abstract olamaz.
  • - Diğer yapılardan daha temel bir mimarisi olması sebebiyle bir Interface sadece başka bir Interface’ten türeyebilir. struct veya class’tan türeyemezler.
  • - Sınıflar sadece tek bir sınıftan ama sınırsız sayıda arayüzden türeyebilir. Arayüzler bu özelliği sebebiyle C#’ta kilit bir rol oynamaktadırlar.
  • - Arayüzlerden türeyen sınıflar, arayüzün tüm üyelerini implemente etmelidirler.

Interface’lere Neden İhtiyaç Duyarız?

Interface’ler sınıflarımız için birer kontrattırlar (contract). Ya da bir diğer deyişle sınıfların implemente etmesi gereken kuralları belirlerler. Buradan da şu anlamı çıkarabiliriz; Arayüzler syntax ile impletemetasyonu ayıran yapılardır. Kavramı biraz daha açmaya çalışalım. Arayüzler yukarıdaki kuralda da belirtildği gibi içerisindeki tüm elemanların sınıf tarafında da bulunması zorunluluğunu beraberinde getirir. Fakat arayüzler, sınıfın içerisinde bu elemanları implemente ettiğimizde içerisini nasıl oluşturacağımızı söylemezler. Burada ise sınıfın tasarımı ve implementasyonun nasıl yapılacağı yazılımcıya bağlıdır. Dolasıyla kontrat bir sınıfın uyması gereken kodlar, implementasyon yazılımcının tasarlaması gereken sınıf elemanları olup, interface ise object oriented mimaride bu iki kavramı birbirinden ayıran en temel kavramdır.

Biraz da pratikte arayüzlerin neden gerekli olduğuna bakalım. Senaryomuz gereği TextBox ve DropDownList kontrollerinin olmadığını ve bu kontrollerin kendimiz tarafından yazılacağını varsayalım. Öncelikle mantık olarak bu iki kontrolün ortak özellikleri neler olabilir diye düşünürsek her iki kontrolünde Text ve ID özellikleri (property) ve DataBind isminde bir metod olabilir. Dolayısıyla IControl isminde bir arayüz tasarlayıp bu üç elemanı bu interface içerisine yerleştirebiliriz.

    public interface IControl
    {
        string ID { get; set; }
        string Text { get; set; }
        void DataBind();
    }
    

Şimdi de iki tane farklı sınıf yaratıp bu arayüzü implemente edelim.

    public class TextBox : IControl
    {
        public string ID { get; set; }

        public string Text { get; set; }

        public void DataBind()
        {

        }
    }

    public class DropDownList : IControl
    {
        public string ID { get; set; }

        public string Text { get; set; }

        public void DataBind()
        {

        }
    }
    

Arayüz kullanmamızın ilk faydası sınıflarımızın belirli bir kontrata uymasıdır. Yani iki kontrolün de benzer bir syntaxta kodlanması sağlanmıştır. İşin bu yönden faydasına bakacak olursak karmaşık framework veya uygulamalarda ileride tasarlanacak sınıflar için bir temel oluşturulmuş olur. Projede farklı yazılımcılar çalışacağı veya bu uygulamayı kullanacağı zaman karşısında daha mantıklı ve düzgün kurgulanmış bir yapı bulması projenin anlaşılabilirliğini arttırır. Aynı şekilde arayüzler, yeni sınıflar tasarlanmaya başlanacağı zaman nereden başlanılacağı konusunda yardımcı olurlar.

Diğer bir faydası ise kalıtım vasıtasıyla ortak özellikteki nesnelerin gruplanmış olmasıdır. Çok basit bir örnek vermek gerekirse bir object dizisindeki nesnelerin içerisinde foreach vasıtası ile döndüğümüzü varsayalım. Elde ettiğimiz her bir nesnenin IControl arayüzünden türeyip türemediğini kontrol edip nesneyi bu arayüze türetebiliriz. Böylelikle tek tek tüm türeyen sınıflar için ayrı ayrı bir if deyimi yazmamıza gerek kalmaz.

    foreach (object obj in objArray)
    {
        if (obj is IControl)
        {
            IControl iControl = (IControl)obj;
            iControl.DataBind();
        }
    }
    

Arayüzlerde İsimlendirme

C#’ta arayüzlerin başına ‘I’ harfi konmaktadır. Bu tarz bir isimlendirme .Net Framework altında başka bir yerde görülmemektedir. Dolayısıyla arayüzler bir istisnadır. İsim verirken diğer dikkat etmemiz gereken kısım ise arayüzün ne yaptığı ve türeyeceği sınıf ile nasıl bir ilişki içerisinde bulunduğudur. Genel anlamda sınıflar arasında ‘-dir, -dır’ ilişkisi varken arayüzler ile sınıflar arasında ‘yapabilir’ veya ‘yapar’ ilişkisi bulunmaktadır. Örnek olarak IDisposable (Dispose edilebilir) veya IComparer (Karşılaştırır) arayüzleri verilebilir (Dolayısıyla yukarıda tanımladığımız IControl arayüzünin base class mı yoksa arayüz mü olması gerekliliği başka bir yazının konusudur). Ek olarak bir Interface yazıldığı vakit bu arayüzü kullanan bir sınıfta beraberinde oluşturulması tavsiye edilir. Bu sınıf, arayüzün kullanımı açısından örnek teşkil edecek sınıftır ve isim olarak arayüzün adının ‘I’ takısı olmadan hali verilebilir (Örn: IPersonel arayüzü için Personel sınıfının oluşturulması gibi).

Arayüzlerde Eleman Sayısı

Arayüzlerin kullanılabilir olabilmesi için çok fazla sayıda eleman bulundurmaması gerekir. İmplemente edildiğinde bir dolu property ve metodun sınıfa eklenmesi arayüzü karmaşıklaştırır. Genel olarak ’2 ile 5′ arası eleman arayüzler için ideal sayıdır. Beşten fazla olduğu vakit arayüzün farklı arayüzlere bölünebileceği akıllara gelmelidir. Tek elemanlı arayüzler ise mantık olarak gereksizdir. Bunların yerine Attribute kullanımı tercih edilmelidir.

Elaman sayısını arttıracak temel etmenlerden biri de overload metodlardır. Eğer arayüzde overload metodlar bulundurulması istenirse bunların türeyen sınıfta da tek tek kodlanması gerekliliği sınıfı gereksiz yere şişirebilir. Bu sorunu aşmak için ise extension metotlardan faydalanılır. Overload metotlar doğası gereği bir adet tüm parametreleri barındıran ana metoda sahip olmalıdır. Bu metod arayüze gömülmeli, diğer overload metodlar ise extension metod olarak farklı bir yere yazılmalıdır. Örnek vermek gerekirse;

    public interface IControl
    {
        string ID { get; set; }
        string Text { get; set; }
        void DataBind();
        void DataBind(object dataSource);
        void DataBind(object dataSource, bool ignoreNullData);
        void DataBind(object dataSource, bool ignoreNullData, string dataFormat);
    }
    

Yukarıdaki gibi bir arayüz tasarımında gereksiz yere 4 adet overload metod vardır. Arayüz aşağıdaki gibi tasarlandığında ise bu sorun ortadan kalkmaktadır;

    public interface IControl
    {
        string ID { get; set; }
        string Text { get; set; }
        void DataBind(object dataSource, bool ignoreNullData, string dataFormat);
    }

    public static class ExtensionMethods
    {
        public static void DataBind(this IControl control)
        {
            object dataSource = new ArrayList();

            control.DataBind(dataSource, false, "{0}");
        }

        public static void DataBind(this IControl control, object dataSource)
        {
            control.DataBind(dataSource, false, "{0}");
        }

        public static void DataBind(this IControl control, object dataSource, bool ignoreNullData)
        {
            control.DataBind(dataSource, ignoreNullData, "{0}");
        }
    }
    

Bu şekilde bir tasarım ile arayüzümüz ve türeyen sınıf daha sade bir görünüme sahip olacaktır.

Arayüzler ile ilgili yazdığım bu yazı umarım faydalı olmuştur. Bir sonraki yazıda abstract sınıflar ile devam edeceğiz.



1 Yorum


  1. Mustafa Ekici

    Çok teşekkürler gayet açıklayıcı bir paylaşım, kitap tavsiyesi içinde ayrıca teşekkür.

    Şub 01, 2010 @ 21:34

Yanıtla



SON YAZILARIM

genel
Microsoft Türkiye Açık Akademi

Microsoft tarafından Türkiye'deki ilk ücretsiz online yazılım okulu Açık Akademi açıldı....

genel
Windows Azure Blob Arayüzü

Bir önceki yazımızda Blob servisine kısa bir giriş yapmıştık. Yazıyı okumak isterseniz

genel
Windows Azure Blob Servisi

Microsoft'un bulut mimarisi Windows Azure platformu üzerinde veri altyapısı alışıla gelmiş yöntemlerden...