Bu yazımda C#’ta interface yani arayüzlerden bahsedeceğim.Bireysel çalışmalarımızda pek kullanmayacağımız bu yöntemin, takım çalışmalarında çok önemli yeri vardır.Öncelikle şunu belirtmek isterimki Interface bir class değildir.Interface sadece yapı belirtir.Yani o interfaceden kalıtım alan classların barındırması gereken metod,property vs. gibi elemanları belirtir.Bu konuyu ilk öğrenirken Abstract sınıfıyla Interface arasındaki farkı merak edebilirsiniz.Interface bir binanın planıdır.Salon şurada olacak,mutfak burada vs..Abstract sınıfı ise bir evin içi tamamlanmamış halidir.Mesela salon bitmiş ama mutfak bitmemiş.
Bir zorunluluk olmamakla beraber interface isimlerinin başına I konulması tavsiye edilir.Örn,IDunya.Bununla beraber bir yapının interface olduğu kolayca anlaşılabilir.
Interfaceler, kendisinden kalıtım alan sınıfların içinde olması zorunlu olan yapıları tanımlarlar.Tek görevleri budur.Interfaceler bu yönleriyle abstract classlara benzerler.Ancak abstract class içerisinde,kendisinden kalıtım alan sınıfta yazılması zorunlu olmayacak yapılar da tanımlanabilir.Fakat interface tanımlanan herşey, kalıtımı alan sınıfta uygulanmak zorundadır.Yine abstract classlarda olduğu gibi burada tanımlanan yapıların gövdeleri yazılmaz.Gövdeler, kalıtım alan sınıfta yazılır.
Bir class sadece tek bir classtan kalıtım alabilirken, aynı anda birden fazla interfaceden kalıtım alabilir.
Bir class aynı anda her bir classtan hem de bir ya da birden fazla interfaceden kalıtım alabilir.Ancak kalıtımı yazarken ilk önce classdan kalıtım almalıdır.Yani class : A_Classi,B_Interfacei,C_Interfacei şeklinde.
Interfaceler içinde metod,property ve indexer gibi yapılar tanımlanabilirken , constructor v.s gibi yapılar tanımlanamaz.
Interfaceler içinde static yapılar OLAMAZ.
Interface içindeki yapıların public,private,protected v.s gibi erişim belirleyicileri olmaz.Bu yapılar türeyen classlarda yazılırken erişim belirleyicileri orada belirlenir.
Şimdi buraya kadar Interfaceler hakkında genel bilgilendirmede bulundum.Bir sonraki sayfada Interfaceleri C# üzerinden inceleyelim.
Şimdi bu sayfada C# üzerinden interface yapısınının nasıl kurulduğunu anlatacağım.Öncelikle class yerine interface yazmamız gerekiyor.Aşağıdaki bir interface yapısıdır.
interface ISeriler
{
}
Şimdi bir senaryo yazalım.
Benim bir yazılım şirketim olsun.Adları Ahmet ve Ayşe olan iki çalışanım olsun.Şimdi toplantıda Ahmet ve Ayşe’ye yapacağımız projeden bahsedeceğim.Elimde aşağıdaki gibi bir interface im var.
interface ISeriler
{
int SonrakiniGetir();
int Sınıfla();
int BaslangicDegeriniVer(int baslangic);
int Sonraki
{
get;
/*Bu sınıftan kalıtım alan sınıf bu propertyi mecbur kullanacaktır.Ve bu propertyde sadece get bloğu mecbur olacaktır.
set bloğunuda kafamıza göre yazalım dersek onu kabul etmeyecektir.Abstract sınıfındaki farklardan biri budur.*/
}
}
Yukarıda gördüğünüz interface yapısını inceleyiniz.Bütün elemanların erişim belirleyicileri yazılmamıştır.Ve metodların ve propertydeki get setlerin gövdeleri tanımlanmamıştır.Bunların hepsi Interfacein kurallarıdır.Bu sınıftan kalıtım alacak olan sınıfta hem erişim belirleyicileri tanımlanacak , hem de elemanların gövdeleri yazılacaktır.Neyse senaryoya devam edelim.
Ahmet ve Ayşe bu interfacei incelerken ,bir yandan beni dinlemektedirler.”Ahmet ve Ayşe bu interfacei kullanıp,ikiser ikiser ve üçer üçer sayma yapan programları yazmanızı istiyorum.Ahmet sen ikiser ikiser sayacak olan programı , Ayşe sende üçer üçer sayacak olan programı yaz.” diyorum.Artık Ahmet ve Ayşe bu interface e bağlı olarak bu programları yazmak zorundadırlar.
Şimdi Ahmet’in yazdığı ikiser ikiser sayan classını inceleyelim.Ardında Ayşeye bakarız.
Ahmet bu classı IkiserIkiser.cs sayfasında tasarlıyor.
Ben şimdilik implement interface ‘ISeriler’ seçeneğini kullanarak implement etmeyi göstereceğim.Bu seçeneği seçtiğiniz zaman ISeriler interfaceindeki elemanlar aşağıdaki gibi gelecektir.
class IkiserIkiser:ISeriler
{
public int SonrakiniGetir()
{
throw new NotImplementedException();
}
public int Sınıfla()
{
throw new NotImplementedException();
}
public int BaslangicDegeriniVer(int baslangic)
{
throw new NotImplementedException();
}
public int Sonraki
{
get { throw new NotImplementedException(); }
}
}
Yukarıda gördüğünüz şekilde gelen elemanları , Ahmet istediği şekilde programlıyor.(içindeki throw lu ifadeleri silip kendi yazıyor)
class IkiserIkiser:ISeriler
{
int baslangic;
int deger;
//Gördüğünüz gibi kalıtım alan sınıfta , interfacede olmayan elemanlar yazılabiliyor.
public int SonrakiniGetir()
{
deger = deger + 2;
return deger;
}
public int Sınıfla()
{
baslangic = 0;
deger = baslangic;
return deger;
}
public int BaslangicDegeriniVer(int baslangic)
{
this.baslangic = baslangic;
deger = baslangic;
return deger;
}
public int Sonraki
{
get
{
return SonrakiniGetir();
}
}
}
Artık Ahmet interfacee uygun halde classını kodlamıştır.Şimdi Ayşe’nin yaptığı işe bakalım.
Ayşe ise interfacedeki elemanları UcerUcer.cs classında tasarlıyor.
implement interface ‘ISeriler’ ile ISeriler intefaceinden elemanları implement ediyor.Ve aşağıdaki classı programlıyor.
class UcerUcer:ISeriler
{
int baslangic;
int deger;
public int SonrakiniGetir()
{
deger = deger + 3;
return deger;
}
public int Sınıfla()
{
baslangic = 0;
deger = baslangic;
return deger;
}
public int BaslangicDegeriniVer(int baslangic)
{
this.baslangic = baslangic;
deger = baslangic;
return deger;
}
public int Sonraki
{
get
{
return SonrakiniGetir();
}
}
}
Ahmet ve Ayşe interface e uygun classlarını tasarladılar ve önüme koydular.Şimdi şunlara dikkat etmenizi istiyorum.İkiside aynı interfacei kullandıkları için ikisinin classında da metodlar,propertyler vs. gibi elemanların isimleri aynı oldu.Yani Ahmet’in yazdığı IkiserIkiser.cs classında int baslangic parametresi alan BaslangicDegeriniVer() metodu varken, Ayşe’nin yazdığı UcerUcer.cs classında da int baslangic parametresi alan ve BaslangicDegeriniVer() metodu var.
Şimdi bir müşteri gelip benden ikişer ikişer sayan bir program istedi.Ben hemen IkiserIkiser.cs sınıfını kullarak bir program hazırlıyorum.
IkiserIkiser nesne = new IkiserIkiser();
nesne.BaslangicDegeriniVer(2);
for (int i = 0; i < 5; i++)
{
MessageBox.Show(nesne.SonrakiniGetir().ToString());
}
Ve aynı müşteri gelip, ikişer ikişer sayan programdan vaz geçtiğini, üçer üçer sayan program istediğini söyledi.Bende yeni bir program yazana kadar yukarıdaki kodların sadece sınıf adını değiştiriyorum.
UcerUcer nesne = new UcerUcer();
nesne.BaslangicDegeriniVer(2);
for (int i = 0; i < 5; i++)
{
MessageBox.Show(nesne.SonrakiniGetir().ToString());
}
Interfacein bize sağladığı esnekliğin farkına varmışsınızdır umarım.
Buraya kadar ki kısım interfacee giriş niteliği taşımaktadır.Bir sonraki sayfada olası bir kaç durumdan bahsedeceğim.
Şimdi 3 tane interface oluşturalım.
interface IA
{
void Metod1();
void Metod2();
}
interface IB
{
void Metod3();
void Metod4();
}
interface IC
{
void Metod4();
void Metod5();
}
interface ID:IC
{
void Metod6();
void Metod7();
}
Şimdi yukarıdaki IB ce IC interfacelerini inceleyiniz.Dikkat ederseniz ikisinde de aynı isimde Metod4() vardır.Ve ID interfacei IC interfaceinden kalıtım almaktadır.Bir interface, başka bir ya da daha fazla interfaceden kalıtım alabilir.Bu durumda bu interface , kalıtım aldığı interface içindeki elemanları uygulamak zorunda değildir.Fakat, ID interfaceinden kalıtım alan bir sınıf bu durumda hem IC den hem de ID den elemanlarını mecbur uygulamak zorundadır.Interfaceleri birbirinden türeterek programımızda genişletme işlemini kolayca sağlayabiliriz.
Şimdi şuna dikkat edelim.IB cs IC interfaceleri içinde Metod4() imzasına sahip metodlar vardır.Yani ikisinde de aynı isimde metod vardır.IB ve IC den aynı anda kalıtım alan sınıflar içinde Metod4() olduğu kesindir.Ama bunun hangi interface tarafından uygulattırıldığı kesin değildir.İşte bu gibi yapılara(aynı isimde, değişik interfacelerde tanımlanan yapılara) name hiding (isim saklama) ya uğramış yapılar diyoruz.
Şimdi bir AClassi.cs isminde class oluşturalım ve IB ve IC interfacelerinden kalıtım almasını sağlayalım.Sonrada kalıtım aldığı sınıflardan elemanları implement yapalım.
class AClassi:IC,IB
{
public void Metod4()
{
throw new NotImplementedException();
}
public void Metod5()
{
throw new NotImplementedException();
}
public void Metod3()
{
throw new NotImplementedException();
}
}
Yukarıda gördüğünüz gibi öncelikle IC den implement yapıyorum, Metod4() ve Metod5() geliyor.Sonra IB den implement yapıyorum Metod4() var olduğu için sadece Metod3() geliyor.Şimdi ben bu Metod4() ün IC interfaceinemi yoksa IB interfaceinemi ait olduğunu nasıl anlayacağım.(name hiding)Tabikide anlayamayacağım.Bu sorunu çözmek için şu yolu izliyoruz.
Interface üzerine gelince mavi imleçten bu sefer Explicitly implement interface ‘ISeriler’ seçeneğini seçiyoruz.IB ve IC için Explicitly implement yapıyoruz.
class AClassi:IC,IB
{
void IC.Metod4()
{
}
void IC.Metod5()
{
}
void IB.Metod3()
{
}
void IB.Metod4()
{
}
}
Gördüğünüz gibi IB ve IC interfalerini bu classa explictly olarak implement ettim.Eğer bir interface explicitly implement edilirse, içindeki yapılar private olarak alınır.Ve görüldüğü gibi hangi interfaceden geldikleri de bellidir.Böylece name hiding aşılmış olur.
Fakat explicit implementten dolayı elemanlar private gelecek ve bu class nesneleri üzerinden erişelemeyecek.Eğer tutup başlarına manuel olarak public yazmaya kalkarsak da hata veriyor.Yani manuel olarak elle hiç bir müdahale edemiyoruz.İşler iyice çığırından çıkıyor gibi ama sakın telaşlanmayın.
Bu durumda şu işlemi yapacağız.
Yukarıdaki duruma dikkat edersek eğer, AClassi içinde tanımlı olan metodlar çok biçimliliği kullandığımız halde gözükmektedirler.Bunun sebebini sormayın 🙂 Interface de bu şekilde bir kullanım vardır.
Şimdi diğer sayfada başka bir yöntem daha gösterip Interface mevzusunu kapatacağım.Benimde başım çatladı 🙂
Şimdi iki interfaceim olsun ve içinde aynı isimden metodumuz olsun.
interface IA
{
int Metot(int x);
}
interface IB
{
int Metot(int x);
}
Şimdide bunlardan kalıtım alacak bir sınıf oluşturayım.Bunları mecburen Explicitly implement edeceğim.(name hiding olmaması için)
Deneme.cs sınıfında oluşturuyorum.
class Deneme:IA,IB
{
int IA.Metot(int x)
{
return x + x;
}
int IB.Metot(int x)
{
return x * x;
}
}
Yukarıdaki metodları name hiding olmaması için mecburen Explicitly implement ettik.Böylece gelen elemanlar private oldu ve budurumda bu metodları bu class nesnesi üzerinde nasıl kullandıracağız bunu göstereyim.
Deneme.cs sınıfına public olan iki tane metod yazıyorum.
public int MetotA(int a)
{
IA a_ref = this;
return a_ref.Metot(a);
}
public int MetotB(int a)
{
IB b_ref = this;
return b_ref.Metot(a);
}
Yukarıdaki yapıyı incelerseniz eğer, bu classtan dısarıya acılan iki metod sayesinde , private metodları kullanabiliyorum.
Umarım anlattığım interface yapısından yararlanırsınız.Benden bu kadar ..
Bir sonraki yazımda görüşmek üzere..
İyi çalışmalar…