Serkan Ayyıldız

Meraklı bir yazılım uzmanı...

C# Interface Kullanımı ve Çoklu Kalıtım Almak

C#.Net meraklısı yazılım uzmanlarına yeniden selamlar :)

Nesne yönelimli programlama (oop) konusunda C# programlama dili ile ilerlediğimiz bu makale dizimizde bugün biraz uzun bir makale olan interface (arayüz) kavramını inceleyeceğiz.

Her ne kadar interface sözcüğünün anlamı Türkçe'de "arayüz" anlamına gelsede aslında ilk aklımıza gelen görsellikle hiçte alakası yok.Neden arayüz deniliyor derseniz cevap çok uzakta değil..

Interface, kendisinden kalıtım alacak bir sınıfın ana hatlarını belirler.
Örneğin bir sınıfın içerisinde property'ler,metotlar vs. yer alacaksa bunları sınıfın içine yazmak yerine interface denilen yapıya yazar ve bu interface'den defalarca istediğimiz sayıda sınıfa kalıtım vererek ana hatlarını belirleriz.

Buraya kadar bahsettiğim konu aslında interface yapısının basit bir özeti oldu ama aklınızda ufak kıvılcımlar yansın istedim,hatta bazı çizgi filmlerde insanın kafasında ampül felan yanar ya onun gibi bişey :)

Makalemize tekrar dönelim..Daha önce öğrendiğimiz C# class (sınıf) yapısında dikkatinizi çeken bir nokta olmuştur; bir sınıf yalnızca başka bir sınıftan kalıtım alabiliyor ama birden çok sınıftan kalıtım alamıyor.
Dolayısıyla hem annemizden hem de babamızdan kalıtım alamıyor gibi bir durum ortaya çıkıyor ve programlama konusunda dar boğaza sebep oluyor.Hal böyle olunca nesne yönelimli programlamayı geliştiren yazılımcılar bir sınıfın birden çok yapıdan tek seferde kalıtım alabilmesini istemişler ve interface kavramını ortaya çıkarmışlardır.

Az öncede dediğim gibi interface, kendisinden kalıtım alacak olan sınıfların ana hatlarını içerir ancak interface içerisine örneğin metodun ne yapacağı yazılmaz.Yani detaycı bir yapı değildir.

Gelin şimdi Visual Studio'yu açalım ve interface ile ilgili güzel bir örnek proje geliştirelim :)
Yazılımcıda olsak teknik anlamda orta düzeyde bilgisayarcı (ya da diğer anlamıysa IT'ci) sayılırız ve bu projemizde toplama bilgisayar yapalım..
Öncelikle Bilgisayar adında boş bir class oluşturalım :

c#-sınıf

c#-class

c#-sınıf-oluşturma

Şimdi bilgisayar bileşenlerini hatırlayalım; bir bilgisayarın işlemcisi,ram belleği,hard diski,ekran kartı,ses kartı,anakartı gibi parçaları olur.Bu parçaların her birini sınıf olarak programlarsak maalesef bilgisayar sınıfımız her birinden aynı anda kalıtım alamaz çünkü bugünkü anlamda nesne yönelimli programlama tekniğine aykırı olur.
O halde her bileşeni birer interface olarak kullanarak kalıtım alabilmek oldukça akıllıca olacaktır :)

İlk kez interface konusunu okuduğunuzu varsayarak işlemci isminde ilk interface'imizi oluştururken adım adım gideceğiz..Öncelikle aşağıdaki gibi interface oluşturalım:

c#-interface

c#-arayüz

Interface'ler konusunda bilmemiz gereken ilk genel kültür konusu ise interfacelerin adının başına "I" büyük harfle (Ispartanın I'sı) konulması gerektiğidir.Böylece Solution Explorer penceresinden bir dosyanın interface'mi yoksa class'mı olduğunu kolaylıkla anlayabiliriz,bunu yapmakta zorunlu değilsiniz ama büyük çaplı projelerde büyük fayda sağlar. ;)

İşlemci interface'ine sınıfımızdan kolaylıkla erişebilmek adına access modifer'ı (erişim belirleyicisi) public (her yere açık) olarak değiştiriyoruz:

public-interface

Şimdi diyoruz ki; bir bilgisayar işlemcisinin neyi olur? Yani işlemcimize ait bir property (özellik) belirleyeceğiz..Örneğin işlemcinin hızını double cinsinde belirleyelim:

double-interface-value

Interface ile ilgili çok iyi bilmemiz gereken 2 nokta var; birincisi interface'in kendisi az önce yaptığımız gibi public konumda dışarıdan erişilebilir olabilir ancak içerisindeki property ve metot gibi üyelere asla ve asla sınıf oluştururken yaptığımız gibi public,private,protected gibi erişim belirteçleri yazamayız.
Bunun nedeni interfaceden kalıtım alan bir sınıfın kalıtım aldığı her şey sonradan public olarak belirlenmek zorundadır.
Dolayısıyla daha yolun en başında "işlemcinin hızı private (özel) olarak sınıf dışından erişilemeyecek" gibi şart koşamıyoruz.

İkinci bilmemiz konu ise metotlarla ilgili..Interface içerisine yazılan metodun başına public gibi erişim belirteçleri yazamadığımız gibi içeriğini de yazamayız.Bunun yerine metodun tipini (void gibi) yazdıktan sonra adını yazarak kod satırını kapatmak zorundayız.Bunun sebebi ise interface iş yapan yapı değil işi belirleyen yapıdır.
Bu sözümü unutmayın derim ;)

Şimdi işlemcimize uygun bir metot yazalım; örneğin hesapla isminde bir metot yazalım ama kesinlikle aşağıdaki
gibi scope'lar (süslü parantezler) açmadan kapatıyoruz:

interface-metod

Çok basit bir manada bir interface oluşturduk ve bu interface'imiz görüldüğü gibi bir property ve bir de metot
içeriyor..Şimdi gelelim oluşturulan bir interface nasıl kullanılır görelim...

Bilgisayar classımıza geri dönüyoruz ve tıpkı daha önce öğrendiğimiz gibi sınıfımızın adının yanın iki nokta ile
interface'imizin adını yazıyoruz:

interface-kalıtım

Ardından Visual Studio bize implicitly (doğrudan) mi yoksa klasik kodlama(implement) mı kalıtım alacağımızı soruyor.Bu şu demektir: işlemci interface'inden alacağımız kalıtım ile sınıfımıza gelecek olan property ve metot gibi üyelerin nereden geldiğini detaylı olup olmayacağını soruyor.Daha sade bir anlatımla her üye hangi interface'den geliyorsa başına o interface'in yolunu ve adını yazar.

Bu örneğimizde gerek duymadığımız için klasik seçeneğini  seçtikten sonra sınıfımızın property ve metotları şu şekilde geliyor:

interface-property



Metotlara bakarsak sanki elle yazmış gibi otomatik bir şekilde gayet güzel geliyor ancak property'ler o kadar basit
bir şekilde gelmiyor ve Visual Studio diyor ki; 

Nasıl ki interface'den gelen metodun içi boş geliyor ve içeriğini istediğin gibi yazıyorsan, interface'den gelen
property'leri de aynen o şekilde kullan..
Bu yüzden her property ve metodun içeriğinde başlangıç olarak Throw new NotImplementedException (kodlanmamış yeni bir istisnai durum yürüt - göz göre göre hata ver ki yazılımcı eksik kod yazdığının farkına varsın)


Tam da böyle bir cümlenin ardından field (alan) adında yeni bir kavramla karşılaşıyoruz.Field denen küçük yapıyı global
bir değişken olarak düşünebilirsiniz ve field'ler property'lerin kendilerine anlam kattıkları mini minicik nesnelerdir :)

Örneğin işlemciminizin hızını nasıl double cinsinde gösteriyorsak hemen double tipinde bir field oluşturalım:

interface-field

Bu field'in başına public gibi erişim belirleyicisi koymadık çünkü bu sınıf dışında dışarıdan bu field'e erişmek için yine double tipindeki işlemci hızı property'sini kullanacağız.O yüzden field'lerin genel yazılım kodlama standartlarındaki
yeri property'ninkiyle oldukça yakın durur.

Şimdi hız isimli property'mize odaklanıyor ve get ile set adında iki yeni daha kavram görüyoruz:

property-get-set

Get'in Türkçe karşılığı (elde etmek), set'in Türkçe karşılığı ise (ayarlamak,tanımlamak,kurmak) şeklindedir.Get o property'den dışarıya vermek istediğimiz değeri temsil ederken, set ise o property'nin alacağı değeri temsil eder.Yani get ve set bir property'nin değer alıp verebilmesini sağlar.

Hız property'mizin get bloğuna _hiz isimli field'ımızı tanımlıyor ve return sözcüğüyle geri döndürüyoruz.Aslında demek istediğimiz olay şudur:bu metot _hiz isimli field'in değerini geri döndürür.

Set bloğuna ise _hiz field'ımıza dışarıdan bir değer (value) yüklenebilmesini istiyoruz:

interface-property-get-set

Bir property'nin get ve set kısımları oldukça esnek oldukları için istediğiniz gibi kullanabilirsiniz.Mesela hızın _hiz*10 ile
10 katını get bloğunda return diyerek geri döndürebildiğiniz gibi set bloğunu kaldırarak _hiz field'ına bir değerin verilmesini engelleyebilirsiniz.

Bilgisayar sınıfımızın son haline bakalım:

interface-kalıtım-sınıf

Neyse konumuza geri dönelim ve yukarıdaki gibi bir interface'den kalıtım aldık ve interface'den kalıtım aldığımız nesneleri
kullanabildik ancak konumuzun asıl can damarına şimdi geliyoruz :)

Bir sınıf birden çok interface'den kalıtım alabilir ve aldığı her interface'den gelen property ve metotları bünyesinde barındırabilir.Bu sayede tek bir sınıftan kalıtım alabilmenin ötesine geçer..
Şimdi Ram isimli bir interface daha oluşturuyor ve içerisine bellek boyutu ile bellek tut isimli birer property ve metot yazıyoruz:

interface-metod

Yeniden bilgisayar interface'ine geri dönüyoruz ve daha önce işlemci interface'inden kalıtım alan sınıfımızın yanındaki işlemci isminin yanına bir virgül koyarak ram isimli interface'imizin adını yazıyoruz:

interface-çoklu-kalıtım

Tıpkı işlemci interface'inde olduğu gibi klasik kalıtım seçeneğini seçtiğimizde ram interface'inden gelen property ve metodumuzun bilgisayar sınıfına kalıtım alındığını görüyoruz:

interface-kalıtım-metod

Ram boyutunu int tipinde bir property'de tanımladığımız için dışarıdan atanacak olan değeri ve dışarıya göndereceğimiz değeri sınıfımızın bünyesinde tutabilmek adına aynı tipte bir field daha tanımlıyor ve property içerisinde önceki örneğimizdeki gibi bildiriyoruz:

interface-field-oluşturma

Bu defa ekran kartımız için bir interface daha oluşturuyor ve içeriğine çekirdek adı isimli string tipte bir property ve görüntüle isminde bir metot yazıyoruz:

string-field-interface

Ekran kartı interface'imizden de bilgisayar sınıfımıza kalıtım alıyor ve string tipte olan property'mize yine string tipte bir
field oluşturuyor ve property içeriğine yazıyoruz:

property-field-ilişkisi

property-field

Artık bilgisayar sınıfımızı kullanmaya hazırız :)

Windows Formumuzun Form Load eventine geçiyor ve sınıfımızı çağırıyoruz:

sınıf-instance

Bazı meslektaşlarımın interface konusundaki makale ve videolarını incelediğimde sanki interface'den kalıtım alan sınıfın new sözcüğüyle instance (örnek kopya) alırken yeniden aynı interface'e atama yapıldığını görüyoruz.Siz siz olun kendinize;

Interface arayuz=new Sinif();

gibi eziyetler yapmayın :)

Gördüğünüz gibi interface'ler içerisine ne yazdıysak hepsi birer birer tek sınıf altında gayet güzel bir şekilde geldi,biz de bu üyelere değerler verelim ve metotlarını da çağıralım:

sınıf-örneği

Projemizin kaynak kodlarını 

bu linktenbilgisayarınıza indirebilirsiniz,tabi bu arada projemizi Visual Studio 2013 ile geliştirdik ve Visual Studio sürümünüz 2013'ün altındaysa açamayabilirsiniz.
Bir başka dipnot ise bilgisayar isimli sınıfımızın metotlarının içeriğinde "throw new notimplementedexception" yazdığı için bu projeyi çalıştırmadan önce o cümleyi silin,aksi halde proje çalıştığı anda runtime hatası verecektir ;)

Böylece interface konusunun da sonuna gelmiş bulunuyoruz,artık bir sonraki makalemizde görüşmek üzere hoşçakalın esen kalın :)





5 Yorum:

  1. M. Akbaş
    12/4/2014

    Çok teşekkürler, çok yararlandım.

  2. Efsane
    6/14/2015

    Makale guzel.. Fakat siteden gozumu alip, makaleye odaklanamadim.. Muhtesem tasarim :D

  3. harrr
    5/7/2014

    makalede iş yok ama site enterasan olmuş :D

  4. bekir
    5/19/2014

    interfacenin amacı sadece anlattığın gibi kural koymak değil. interfaceyi yeniden örneklemek iki sınıftada kullanım kolaylığı sağlar.nesne yönelimli yzılımın amacıda bu. sınıfları ötelemek ve bağımlılığı azaltmak.eklentiler gibi.ama yinede çok güzel anlatmışsın.eline sağlık.

  5. yusufmskt
    3/11/2014

    Gerçekten güzel ve hitabı geniş bir makale olmuş, bizlere devamını dilemekten başka bir görev düşmez, saygılar...

Bir yorum bırak E-posta adresiniz yayınlanmayacaktır.

Menu