29
Mar'14

OOP 9: Abstract Kavramı ve Abstract Class (C# ile OOP)

Bu yazımda abstract(sanal) kavramına ve abstract sınıflara değinmeye çalışacağım.

 

Tabiki her şeyden önce böyle bir kavrama neden ihtiyaç duyduğumuzu araştırmak gerekir. Bunun için şimdiye kadar anlattıklarımdan fazlasını içermeyen bir yapı kuralım. Mesela elektronik eşya sınıfı ve bu sınıftan türemiş telefon ve bilgisayar adında iki adet sınıf olsun. İlk ihtiyacımız da bu eşyaların fiyatlarının hesaplanması olsun. Sınıfların içine bu fiyat hesaplama metodlarını da kodlayalım. Sonra ihtiyaçlarımızı biraz daha şekillendireceğiz. Anlatmaya çalıştığım yapının kodları aşağıdaki gibi olacaktır:

class ElektronikEsya
{
    public decimal Alisfiyati { get; set; }
    public decimal KarYuzdesi { get; set; }

    public decimal FiyatHesapla()
    {
        return Alisfiyati + (KarYuzdesi * Alisfiyati);
    }
}

class Telefon: ElektronikEsya { }

class Bilgisayar: ElektronikEsya { }

Main içerisini ise aşağıdaki şekilde kodlayarak telefon ve bilgisayar için fiyat hesaplaması yaptıralım.

static void Main(string[] args)
{
    Telefon telefon = new Telefon() 
    { 
        Alisfiyati = 1100, 
        KarYuzdesi = (decimal)20/100 
    };
    Console.WriteLine("Telefon fiyat: {0}", telefon.FiyatHesapla());

    Bilgisayar bilgisayar = new Bilgisayar() 
    { 
        Alisfiyati = 2000, 
        KarYuzdesi = (decimal)25/100 
    };
    Console.WriteLine("Bilgisayar fiyat: {0}", bilgisayar.FiyatHesapla());
}

Programı çalıştırdığımızda çıktı aşağıdaki gibi olacaktır.

oop9ilkFiyat
Fiyat hesaplama yapabilmek için base classtaki ortak bir metodu kullandık. Her ürün için aynı fiyat hesaplama yöntemi varsa bu iyi bir yol olabilir fakat ürünler için farklı farklı fiyat hesaplama yöntemlerine ihtiyaç duyabiliriz ve tüm ürünler için fiyat hesaplama metodu bir zorunluluk olabilir. Bu durumda base class’taki metodu virtual yapıp child class’ta override edebiliriz ama override etmeme lüksüne de sahibiz:) İstediğimiz, child class’ın bu metodu kullanmaya zorunlu olması. İhtiyacımızı karşılayan anahtar kelime abstract anahtar kelimesidir.

 

Biraz abstract anahtar kelimesinden bahsettikten sonra örneğe devam edebiliriz. Maddeler halinde sıralarsak:

 

– Abstract anahtar kelimesi hem metodlar için hem de classlar için kullanılabilir.

– Bir metodun abstract olarak işaretlenebilmesi için sınıfının da abstract olarak işaretlenmiş olması gerekmektedir.

– Abstract bir sınıf, hem abstract hem de abstract olmayan üyeler içerebilir.

– Abstract metodların gövdeleri ancak child sınıflarda kodlanabilir. Metodların gövdeleri abstract olarak işaretlendikleri abstract sınıflarda kodlanamazlar.

20
Şub'14

OOP 8: Base Ctor Çağırımları, Base Ctor’a Parametre Geçirme, Base, Override, New Anahtar Kelimeleri (C# ile OOP)

Bu yazımda kalıtıma kısa bir giriş yaparak, kalıtım uygulanmış bir yapıda ctor çağırımlarının hangi sırada gerçekleştiğini, base ctor’a nasıl parametre gönderildiğini, bazı anahtar kelimelerin(base, override, new) ne işe yaradıklarını ve kullanımlarını açıklamaya çalışacağım.

 

Kalıtım hakkında bilgi sahibi olmak için bir önceki yazım olan OOP 7‘yi okuyabilirsiniz. Eğer hazırsak kalıtıma kısa bir giriş ile başlayalım.

 

Girişte bahsettiğim konulara açıklık getirebilmek için elbette kalıtım uygulanmış bir yapıya ihtiyacım var. Eşya sınıfından türetilmiş elektronik eşya sınfı ve elektronik eşya sınıfından türetilen iki adet sınıfımız(telefon, bilgisayar) olsun.

Class View

Kalıtım Uygulanmış Sınıflarda Ctor Çağrım Sırası

Bu sınıfların her biri içerisine bir ctor kodlayalım ve her ctor, çağırıldığında kim olduğunu bize söylüyor olsun. Son durumda kodladığımız sınıfların içerisi şu şekildedir:

class Esya
{
    public Esya()
    {
        Console.WriteLine("Eşya sınıfının yapıcı fonksiyonu çağırıldı.");
    }
}

class ElektronikEsya : Esya
{
    public ElektronikEsya()
    {
        Console.WriteLine("ElektronikEsya sınıfının yapıcı fonksiyonu çağırıldı.");
    }
}

class Telefon : ElektronikEsya
{
    public Telefon()
    {
        Console.WriteLine("Telefon sınıfının yapıcı fonksiyonu çağırıldı.");
    }   
}

class Bilgisayar : ElektronikEsya
{
    public Bilgisayar()
    {
        Console.WriteLine("Bilgisayar sınıfının yapıcı fonksiyonu çağırıldı.");
    }
}

Main class içerisinde de Telefon sınıfından bir nesne yaratarak ctor çağırımlarının sırasını inceleyelim.

static void Main(string[] args)
{
    Telefon telefon = new Telefon();
}

Program çalıştırıldığında aşağıdaki çıktı alınır.

CtorCagirimiSirasi

Gördüğünüz gibi ilk önce kalıtım ağacının en tepesindeki sınıfın yapıcı fonksiyonu çağrıldı. Ardından sırayla child class’lara doğru inilerek base class yapıcı fonksiyonları sıra ile çağrıldı.

Base Ctor’a Parametre Gönderilmesi

Base ctor’a parametre göndermek için base anahtar kelimesi kullanılır. Bu anahtar kelimeyi sınıfımızın ctor tanımının yanına “:” koyarak yazarız ve parantezler arasına base sınıfa göndereceğimiz parametleri belirtiriz.

class BaseClassName
{
    public BaseClassName(int parametre1)
    {

    }
}

// Base class ctor'u integer bir parametre alıyor.
class ChildClassName : BaseClassName
{
    public ChildClassName (int parametre1, string parametre2)
        : base(parametre1) // parametre1 base ctor'a gönderildi.
    {

    }
}

Bu konuya açıklık getirebilmek için ilk örnek üzerinden sınıfların ctor yönlendirmelerini yaparak devam edelim.

class Esya
{
    public Esya(string esyaAdi)
    {
        Console.WriteLine(esyaAdi);
    }
}

class ElektronikEsya : Esya
{
    public ElektronikEsya(int voltaj, string esyaAdi)
        :base(esyaAdi)
    {
        Console.WriteLine(voltaj);
    }
}

class Bilgisayar : ElektronikEsya
{
    public Bilgisayar(string ekranKartiMarkasi, int voltaj, string esyaAdi)
        :base(voltaj,esyaAdi)
    {
        Console.WriteLine(ekranKartiMarkasi);
    }
}

Bir bilgisayar nesnesi yaratarak ctor yönlendirmelerinin doğru şekilde çalışıp çalışmadığına bakalım.

static void Main(string[] args)
{
    Bilgisayar bilgisayar = new Bilgisayar("NVIDIA", 18, "Bilgisyar");
}

Ekran görüntüsü aşağıdaki gibidir:

CtorYonlendirmeleriSonuc

Kısa bir özet:

– Kalıtım yapıldığında ctor çağırımlarının hangi sırada olduğunu ve base ctor’a nasıl parametre geçirildiğini yani ctor yönlendirmelerini inceledir.

26
Oca'14

OOP 7: Kalıtım (Inheritance) (C# ile OOP)

Nesneye yönelik programlamanın yapıtaşlarından biri de kalıtımdır. Kalıtım kelimesi yerine bazen miras alma ya da ingilizcesi olan inheritance kullanılabilir.

 

OOP için kalıtım, bir sınıfın başka bir sınıftan türetilmesidir. Bazı programlama dilleri için bir sınıfın başka bir ya da birkaç sınıftan türetilmesi de mümkün iken c# için bir sınıf sadece başka bir adet sınıftan türetilebilir. Kısaca c# çoklu kalıtıma(multiple inheritance) izin vermiyor.

kalitim0

C# ‘ta kalıtım, adımımızı attığımız her yerdedir:) Nasıl mı? Daha önceki yazılarımdan birinde bahsettiğim gibi; c#’ta her şey object sınıfından kalıtılmıştır. Bir önceki paragrafta dediğimden yola çıkarak, her sınıf sadece bir sınıftan kalıtılıyorsa ve zaten object sınıfından kalıtıldıysa, nasıl bir sınıfı kendi istediğimiz diğer bir sınıftan kalıtacağız? Tabiki böyle bir karmaşa yok. Eğer biz bir sınıfın hangi sınıftan kalıtılacağını belirtmediysek, object sınıfından kalıtılır.

Neden Kalıtıma İhtiyaç Duyulur?

Doğayı nasıl anlamlandırırız? Beynimizde doğadaki canlılar nasıl yer tutar? Özelden genele canlıları nasıl sınıflandırdığımızı görebiliyor muyuz? Tanımlamamız bir köpek olsa da bu tanımın, bir sınıflandırmanın içinde olduğunu biliyoruz. Varlık->canlı->memeli->köpek… Örneğin, kedi ve köpeğin ortak noktası memeliler sınıfından olmak, koşabilmeleri ortak özellikleri. Bu ve bunun gibi ayrımları, genelden özele anlamlandırmaları yapabilme yeteneğine insanoğlu zaten sahip. Yazılıma da bu anlamlandırma yeteneği kalıtım ile kazandırılmaktadır.

 

Kalıtım sayesinde, bir üst sınıftan türetilmiş sınıflar, üst sınıfın istenilen özelliklerini kendilerine alırlar. Bu sayede:

 

– Gereksiz kod yazımından bir nebze olsun kurtulmuş oluruz.

– Kodun anlaşılması daha kolay olur.

– Yazılıma harcanan zaman azalır.(Uzun soluklu projeler için.)

– Sonradan gelebilecek değişikliklere kolay uyum sağlayabilecek esnek kodlar yazılmış olur.

– Sistemin, ek ihtiyaçların kolay entegre olabilmesi mümkün olur.

 

Yukarıdaki maddeler OOP yaklaşımının sağladığı faydalardır aynı zamanda. Tabiki bunlar kalıtımın doğru şekilde uygulanmasıyla mümkündür. Peki kalıtım nasıl uygulanır? Örnek kodlarla beraber bu konuya açıklık getirmeye çalışalım.

Kalıtımın Uygulanması

Birkaç farklı türde taşıtı satabilen bir oto galeri için uygulama yazdığımızı düşünelim. Farklı taşıt türleri için farklı fiyat belirleme ihtiyacı doğacaktır. Biz de her taşıt türü için fiyat hesaplama fonksiyonu kodlayalım en iyisi. İhtiyacımıza göre bir tanesini çağırır fiyatını hesaplatırız. Her şey ne kadar güzel. Sonra fiyat hesaplamadaki yöntem değiştiğinde gidip her fonksiyonu tek tek değiştiririz. Değiştrir miyiz? İşte orda durun! Değiştirmeyin. İyisi mi kodu tamamen silin:). Hatta hiç böyle kodlamayın. Gelin biz, OOP yaklaşımı ve kalıtımı bu problem için nasıl doğru şekilde uygularız bir plan yapalım.

 

İlk önce sınıfların yapısını planlayalım. Farklı türden taşıtları içerebilecek bir taşıt sınıfı olmalı. Örneğin basit olması açısından otomobil ve kamyonet olarak iki farklı taşıt türünü ele alalım. Bu durumda aşağıdaki gibi bir yapıya ihtiyacımız var.

kalitim1

Bir sınıfı başka bir sınıftan türetmek için sınıf adının yanına “:” koyarak miras alınacak sınıfın adı yazılır.

Yukarıdaki diyagram için sınıfların kodları aşağıdaki gibidir.

class Tasit { }

class Otomobil : Tasit { }

class Kamyonet : Tasit { }

İsteğimiz, taşıtlar için fiyat hesaplayabilmekti. Bunu az kod ve esnek bir şekilde halletmek için artık fonksiyonu Tasit sınıfı içerisine kodlayabilir ve diğer sınıfların üzerinden çağırabilirz.

Tasit sınıfının son hali aşağıdaki gibidir.

class Tasit 
{
    public decimal SaatBasinaUcret { get; set; }
    public int Sure { get; set; } // Saat bazında.

    public decimal FiyatHesapla()
    {
        return SaatBasinaUcret * Sure;
    }
}

Şimdi taşıt tipinden bir otomobil belleğe çıkaralım ve property’lerini set ederek fiyatını hesaplayalım.

static void Main(string[] args)
{
    // Object initializer kullanarak property'lere değer atayalım.
    Otomobil otomobil = new Otomobil()
    {
        Sure = 5,
        SaatBasinaUcret = (decimal)5/4,
    };

    Console.WriteLine(otomobil.FiyatHesapla());
}

Aynı şekilde kamyonet sınıfı için de FiyatHesapla metodunu kullanabiliriz. Böylelikle her tip için bir fiyat hesaplama metodu yazmak yerine sadece base class’a yazarak işi tamamlamış olduk.

 

Şimdiye kadar anlatılanlara birkaç ek yapalım ve biraz toparlayalım:

 

– İlk önce kalıtımdan ve kalıtıma neden ihtiyaç duyulabileceğinden bahsettik.

– Kalıtımın uygulanması ile ilgili ufak bir örnek yaptık.

– Base class’taki public bir metodun nasıl alt sınıflardan çağırılabildiğini gördük.

– Erişim belirleyiciler konusunda anlattığım gibi, public elemanlar her yerden erişilebilir durumdadır. Eğer sadece alt sınıfların erişmesini istediğiniz bir eleman varsa protected ile işaretlemeniz gerekmektedir.

Internal protected ile işaretlenmiş elemanlara ise assembly dışından türetilmiş alt sınıflar da erişebilir.

 

– Kalıtımla birlikte değinilmesi gereken diğer konular ise, türettiğimiz sınıfların birinden nesne örneklediğimizde constructor çağırımlarının nasıl yapıldığı, base class ctor’una nasıl parametre gönderildiği, base, override, new anahtar kelimeleri olarak sıralanabilir. Bu konuyu içeren sıradaki yazıyı okumak için tıklayınız.

 

İyi Eğlenceler:)

Yeni makaleleri E-Mail ile takip edin!