CSharp – Nesne Yönelimli Programlama (OOP) Nedir – Tüm Detaylarıyla

Bir önceki yazımızda OOP hakkında genel fikir verici şeylerden bahsedip aslında neye hizmet ettiğini, ne yaptığını ve ne için ortaya çıktığı gibi soruları cevaplandırmış olduk. Şimdi ise nesne yönelimli programlamanın detaylarına ineceğiz. 5 ana başlık altında anlatmaya çalışacağım.

1. Classes & Object (Sınıflar ve Nesneler)

Gerçek hayatta sorun olarak baz alınan modellemeyi ifade eder. Bu sınıflardan aldığımız instance’lar ile de objelerimizi elde ederiz.
Sınıf oluşturma;

class OrnekSinif 
{  
}  

Ayrıca class yerine struct terimi ile de böyle bir örnekleme yapabiliriz. Struct ise daha küçük kapsamlı bir öğeyi betimlemek istediğimizde kullanabiliriz. Örneğin bir kitap veya stok özellikleri gibi bilgiler için kullanılabilir. Büyük hacimler için tercih edilmez.

  • Encapsulation , Properties , Fields (Kapsülleme)

Encapsulation, bir fielda direk erişimi engelleyerek değimi yerindeyse onu sarmallar ve girdi çıktıları kontrol altına alır.

class OrnekSinif 
{  
    private string ornekField;
}
class OrnekSinif 
{  
    //Okuma veya Atama işlemlerinde herhangi bir aksiyon almak istediğinizde get/set'leri kullanırız.
    public string OrnekProperty { get; set; } 
}

Son olarak kapsülleme örneği ise aşağıdaki şekildedir.

class OrnekSinif 
{  
    private string _ornekField;
    public string OrnekProperty
    {  
        // Field'daki data döndürülüyor. 
        get { return _ornekField; }  
        // Field'a data set ediliyor. 
        set { _ornekField = value; }  
    }
}
  • Methods, Overload Methods

Metodlar, bir sınıfa veya nesneye bağlı olarak çalışıp ilgili eylemleri yerine getirirler. Method oluşturma şablonu şu şekildedir:
“Erişim belirleyicisi/dönüş tipi/Metod Adı/(optinal) Parametreler”.
Örnek method oluşturma.

class OrnekSinif 
{
    //Parametresiz
    int OrnekMethod()
    {  
        // kod parçacığı 
        // ... 
        // kod parçacığı 
    }
    
    //Parametreli
    int OrnekMethod(int sayi)
    {  
        // kod parçacığı 
        // ... 
        // kod parçacığı 
    }
}

Aynı method isminde ve farklı parametreler ile oluşturduğumuz methodlara ise Overload Method denir.

class OrnekSinif 
{
    int OrnekMethod(int sayi)
    {  
        // kod parçacığı 
        // ... 
        // kod parçacığı
    }
    
    int OrnekMethod(string a)
    {  
        // kod parçacığı 
        // ... 
        // kod parçacığı 
    }
    
    int OrnekMethod(int sayi, string a)
    {  
        // kod parçacığı 
        // ... 
        // kod parçacığı 
    }
}

Extension Methodlar ve daha fazla method detayını farklı başlıklar altında değineceğiz.

  • Constructor Methods (Yapılandırıcı/Kurucu Method)

Class’dan bir instance oluşturulurken ilk olarak Constructor tetiklenir ve çalışır. Bu instance’a ilişkin olarak alınması gereken aksiyonlar da burada yer alır. Ayrıca constructor methodlar overload da edilebilir.

public OrnekSinif 
{  
    public OrnekSinif()
    {  
        // ctor kod parçacığı 
        // ... 
        // ctor kod parçacığı 
    }

    //ctor overload
    public OrnekSinif(string a, string b)
    {  
        // ctor kod parçacığı 
        // ... 
        // ctor kod parçacığı 
    }
}
  • Finalizers (Sonlandırıcılar)

.Net Framework bu işlemi hali hazırda otomatik olarak yapıyor. Nesnelere destruct uygular, yani yıkar. Bellek yönetimi yapar. Fakat otomatik olarak yapılamayan nesneleriniz var ise bunların destruct yönetimini sizin yapmanız gerekir. Bu başlık kendi başına bir konu aslında GC namespace’i altında inceleyeceğiz.

  • Events (Olaylar)

Nesnelerimiz üzerindeki changed, click gibi olaylarda almak istediğimiz aksiyonlarımızda devreye girer. Bu başlık altında “Delegate”, “+=”, “Invoke” ifadeleri ile çokça karşılaşacaksınız.

  • Nested Classes (İç İçe Sınıflar)

Bir sınıf içerisine tanımlanmış başka bir sınıfı ifade eder. Basitçe şöyle tanımlanır:

class KapsayiciSinif  
{  
    class IcSinif  
    {  
        // kod parçacığı  
    }  
}
KapsayiciSinif.IcSinif icObje = new KapsayiciSinif.IcSinif()
  • Access Modifiers (Erişim Belirleyicileri)

Bir sınıf veya sınıf üyelerinin hangi erişim düzeyinde olacağını belirler.

public :
Bulunduğu class ve dışarıdan tam erişim.

private :
Dışarıdan hiçbir şekilde erişilemez. Sadece bulunduğu class içerisinde erişilebilir.

protected 
:
Bulunduğu class’dan ve bulunduğu class’da türetilen class’lardan erişilebilir.

internal 
:
Bulunduğu assembly(dll veya exe) içerisinden erişilebilir.

protected internal 
:
proctected özelliklerine tamamen sahip ve ayrıca bulunduğu assembly(dll veya exe) içerisinde olmasa dahi tanımlandığı class’dan türetilen tüm class’lardan erişilebilir.

private protected :
private özelliklerini aynen taşır. Artı olarak bulunduğu class’dan türetilen tüm class’lardan da erişilebilir.

  • Instantiating Classes

Sınıflardan obje oluşturmak instance oluşturmak gerekir.

class OrnekSinif 
{  
    public string Property1 { get; set; } 
    public string Property2 { get; set; }

    public int PlusOne(int a)
    {  
        return a + 1;
    }
}

Şimdi bu sınıftan bir instance alma ve kullanma şekillerine bakalım.

OrnekSinif ornekSinif = new OrnekSinif();//Instance oluşturduk.
ornekSinif.Property1 = "Hello";

OrnekSinif ornekSinif2 = new OrnekSinif{ Property1 = "Hello", Property2 = "World" };
//Property Set ederek instance oluşturduk.
  • Static Classes & Members (Statik Sınıflar)

Statik sözcüğü, sınıflar ve üyeleri için herhangi bir instance işlemine gerek duyulmadan direk erişilebilmesini sağlar.

public static class OrnekSinif 
{  
    public static string Property1 = "Hello";
    public static string Property2 = "World";

    public static int PlusOne(int a)
    {  
        return a + 1;
    }
}

kullanımı

//Herhangi bir instance oluşturmadan direk erişebildik.
string metin = OrnekSinif.Property1 + " " + OrnekSinif.Property2;
int sayi = OrnekSinif.PlusOne(1);
  • Anonymous Types (Anonim Tipler)

Herhangi bir veri türü veya class belirtmeksizin oluşturulur. Bu işlemi verilen sınıf veya veri türüne göre sistem otomatik olarak yapar. Fakat bizim bir tür belirtmemize gerek kalmaz tanımlama yaparken.

var obj = new { A = "Hello", B = "World" };

2. Inheritance (Kalıtım, Miras Alma, Devralma)

Bir sınıfın özelliklerinin kalıtım yolu ile başka bir sınıfa aktarılmasıdır.

Bir class yalnızca bir class’ı miras alabilir.

class A //Base class
{

}

class C
{

}

//B class'ı A class'ı özelliklerini devralıyor.
class B:A
{

}


//Bir de yanlış kullanımını gösterelim
class B : A, C // Böyle bir kullanım yoktur. Aynı anda 2 farklı class bu işlem için kullanılamaz.
{

}

NOT: Bu noktada iki farklı konu karşımıza çıkıyor. Birincisi “sealed class” , ikincisi ise “abstract class” kavramlarıdır.

sealed class: sealed olarak tanımlanan bir class, başka bir class’a inheritance(kalıtım, miras alma, devralma) için kullanılamaz. Sadece ilgili bussines’ı veya görevi yerine getirir. Bu sınıfta bulunan herhangi bir method veya member’ın ezilmesini istemeyiz.
abstract class: abstract şekilde tanımladığımız classları base olarak kullanırız. Yani “bir varlığın en temel özelliklerini en ilkel şekilde barındırır” diyebiliriz. Abstract class’lardan instance oluşturulamaz. İçerisine kod yazılabilir. Private olarak tanımlanamazlar. Interface’lerden ayrılan yanlarından birisi de budur.  Ayrıca belirlediğimiz bu temel özellikleri türetilen sınıfta override edip, türetilen class’a uygun şekil almasını sağlayabiliriz.

public sealed class A { } //Sealed class tanımlama

public abstract class B { } //Abstract class tanımlama
  • Overriding (ezme, geçersiz kılma, çiğnemek)

Base class’dan alınan default özellikleri, türetilen sınıfa göre değiştirmek/geçersiz kılmak istiyorsak bu işlemi uygularız.

C# Modifiers: virtual, override, abstract, new Modifier

virtual: Türetilen sınıfta override edilebilmesini sağlar.
override: Türeyen sınıfta override eder.
abstract: Türeyen sınıfta override etmek zorunludur.
new: Türetilen sınıftan devralınan member’ı gizler.

public class BaseClass
{
    public virtual void OzellikYazdir()
    {
        Console.WriteLine("Hello");
    }
}

public sealed Example:BaseClass
{
    public override void OzellikYazdir()
    {
        Console.WriteLine("Hello World!");
    }
}

3. Interfaces (Arabirimler)

Sınıfların kullanacağı özelliklerin sözleşmesinin yapıldığı ara birimlerdir. Bu arabirimleri referans alan tüm class’lar, ilgili sözleşmedeki tüm member’ları kullanmak zorundadır. Bir class birden fazla interface alabilir.

public interface IExample  
{  
    void OrnekMethod();
}


class OrnekSinif : IExample  
{  
    void OrnekMethod()  
    {  
        // kod
        // ...
        // kod
    }  
} 
public interface IEkle
{  
    void Ekle();  
}

public interface ISil
{  
    void Sil();  
}

public interface IDuzenle
{  
    void Duzenle();  
}

public interface IListele
{  
    void Listele();  
}


public class OrnekSinif : IEkle, ISil, IDuzenle, IListele
{  
    void Ekle()  
    {  
        // kod
        // ...
        // kod
    }
    
    void Sil()  
    {  
        // kod
        // ...
        // kod
    }
    
    void Duzenle()  
    {  
        // kod
        // ...
        // kod
    }
    
    void Listele()  
    {  
        // kod
        // ...
        // kod
    }
} 

4. Generics

Generic olarak oluşturulacak öğe, hangi türde oluşturulması isteniyorsa o türü parametre olarak alır ve o işlemi gerçekleştirir. Bize şunu sağlar: Tek seferde yazılan bir işlevi farklı obje türleri için de işlevsel hale getirebilme imkanı verir. Yani birçok iş için bir kere efor harcanır. Gereksiz kod tekrarının önüne geçer.

Generic Sınıf Tanımlama ve Kullanımı

public class ExampleGeneric<T>//T tipi alınıyor.
{
    public T Insert(T model)
    {
        //Insert işlemi
        //....
        return model;
    }
}
ExampleGeneric<TypeName> exam = new ExampleGeneric<TypeName>();

var resultItem = exam.Insert(new TypeName{ /*Properties*/ });

5. Delegates (Temsilciler)

Temsilciler (delegate), bir “t” zamanında, bir “y” aksiyonu dolayısıyla tetiklenmesini istediğimiz aksiyonları almamızı sağlar. Yani örnek vermek gerekecek olursak bir ekranda bir butona bastıktan sonra bu işlemin daha başka methodları da tetiklemesini istiyorsak bu yöntemi kullanabiliriz. Yordam saklamaya yarar. Parametre alması gereken durumlarda parametre de verilebiliyor. Ufak bir örnek kod yazalım.

//------------------------------------------
public delegate void ornekDelegate();

public void Method1()
{
    Console.WriteLine("Method 1");
}
public void Method2()
{
    Console.WriteLine("Method 2");
}
public void Method3
{
    Console.WriteLine("Method 3");
}
//------------------------------------------

//Kullanımı
ornekDelegate ornek = new ornekDelegate(Method1);
ornek += new testDelegate(Method2);
ornek += new testDelegate(Method3);
ornek();//Burası run edildiği zaman ekrana "Method 1", "Method 2" ve "Method 3" basacak.

Bu ve diğer tüm başlıklar hakkında talep ederseniz daha derinlemesine işleyebiliriz. Yazıyı çok uzatmak istemedim. Çünkü herşeyi tek bir başlık altında anlatmak çok uzun sürer.
Sorularınız veya değinmemi istediğiniz konular var ise sorabilirsiniz. Zaman bulabildikçe yanıt vermeye çalışacağım.