Nesne Yönelimli Programlama - Object Oriented Programming (OOP)

Yazılım geliştirmenin altında yatan gerekçe, gerçek hayatta var olan sorunları birler ve sıfırlar dünyasında modelleyerek çözmektir. Modellemek için de farklı yöntemler kullanılabilir. Bunlardan biri nesne yönelimli programlamadır (obje yönelimli programlama) (OOP — Object Oriented Programming).

Nesne yönelimli programlama yaklaşımının altında yatan mantık, gerçek hayatta gördüğünüz varlıkları birer nesneye karşılık gelecek şekilde bilgisayar simülasyonuna aktarmaktır. Bir nesnenin yapabildiklerini veya özelliklerini bilgisayara tanıtmak için OOP üzerinde kullandığımız terimlerden en önemli iki tanesi; sınıf (class) ve arayüz (interface) terimleridir.

Bu makalede yer alan kod örnekleri, nesne yönelimli program geliştirmemize uygun olan C# dilinde olacaktır. Bu örneklerin alındığı projenin amacı ise MarsRover sorununa bir çözüm getirmektir.

Origin: https://en.wikipedia.org/wiki/Mars_Exploration_Rover#/media/File:NASA_Mars_Rover.jpg

Arayüz (Interface)

Yukarıdaki arayüzü implemente eden sınıfların üzerinde GoForward metodu olacaktır. Metodun içerisinde neler yapılacağı, her implemente eden sınıf tarafından kendine has kurallarla yazılacaktır. Rover sınıfı IMovable arayüzünü uygulayıp içerisinde ‘tekerleri döndür’ gibi bir emir yürütürken, Human sınıfı ‘adım at’ gibi bir emir yürütebilir. Nihayetinde, iki nesne de ileri gidebilme yeteneğine sahiptir.

Sınıf (Class)

Sınıf Tipleri

Soyut sınıflar soyut olmayan sınıflar gibi doğrudan kendilerine ait nesneler oluşturamazlar. Soyut sınıflardan türeyen soyut olmayan sınıflar tasarlanır ve bu sınıflar üzerinden örnekler elde edilir. Bu durum yukarıdaki örnek üzerinden açıklandığı zaman daha anlamlı olabilir. Örneğin, NASA’da çalışmaya başladınız. Mars yüzeyine gönderilmek üzere size bir araç talebi gelirse, sanırım aklınıza gelen ilk soru ‘Nasıl bir araç?’ sorusu olur. Bilgisayarda da bu durum geçerlidir. Bir araç oluşturulmak istendiği zaman, Vehicle sınıfının hangi alt kırılımına ait nesne üretilmesi gerektiğine dair muğlak bir durum oluşacağı için soyut sınıflar üzerinden nesne oluşturulamaz.

Soyut sınıfları kullanmamızın bir amacı kod tekrarından kaçınmaktır. Mars yüzeyinden örnek toplayabilecek bir araç tasarlamanız gerekirse Vehicle sınıfından yeni bir sınıf türetmeniz ve TakeSample metodunu yazmanız yeterli olacaktır. Bu şekilde Turn ve GoForward metotlarını tekrar yazmanıza gerek kalmayacaktır. Ayrıca Turn ve GoForward metotlarında bir değişiklik yapılmak istenmesi halinde bu değişikliğin tek bir yerden yapılabiliyor olması, sürdürülebilirlik açısından uygulamanıza pozitif etki yapacaktır.

Soyut sınıfları kullanmamızın bir diğer amacı ise ortak bir yapı ortaya koyabilmektir. Bunu yaparken kullanabileceğimiz özellik ise soyut metotlardır. Soyut metot şu anlama gelmektedir; sınıf bir kabiliyete sahiptir ama bu kabiliyeti nasıl ortaya koyduğu her alt kırılımda farklılık gösterecektir. Her yiğit yoğurt yer ama her yiğidin ayrı bir yoğurt yiyişi vardır.

Bir noktanın yüzey alanı üzerinde iz düşüme sahip olup olmadığı Surface nesnesine sorulabilir. Her yüzey alanı kendine ait bazı kuralları işleterek bu soruya cevap verebilmektedir. MarsRover örneğimizde Platoları dikdörtgen olarak tasarladık. Yüzey alanımız dikdörtgen olduğu için bir noktanın X ve Y değerinin belirlenen minimum ve maksimum değerin arasında olduğunu kontrol etmesi yeterli olacaktır. Surface sınıfının bir alt kırılımı olarak Lowland (ova) sınıfını tasarlamış olalım. Ovaların da üçgen olduğunu varsayalım. Ova sınıfı `bool Contains(Point point)` metodunu kendi kurallarına göre uygulayacaktır ama dışarıdan bakıldığı zaman aynı metot imzasına ova üzerinde de rastlanmış olacaktır.

Kalıtım (Inheritance)

Bir sınıf bir başka sınıfı kimlik endişesiyle kalıtım alır. Örneğin, Human (insan) sınıfı Organism (organizma) sınıfını kendi kimliği gereği üstüne alır. Bir diğer deyişle “insan bir organizmadır” sözcüğünün yazılım dilindeki karşılığı, bir sınıfın başka bir sınıfı kalıtım almasıdır.

Arayüzler ise sergilenen yetenekler gereği üstlenilir. Human sınıfı GoForward veya Think gibi metotları IMovable veya IAbleToThink arayüzleri aracılığıyla elde eder. “İnsan koşabilir” veya “İnsan düşünebilir” demenin yolu bir sınıfın arayüzleri kalıtım almasıdır.

Bir sınıf C# dilinde yalnızca bir sınıfı kalıtım alırken birden fazla arayüze ait davranışı sergileyebilir. Ayrıca bir sınıf hem başka bir sınıfı kalıtım alıp hem arayüz implementasyonu yapabilir. “İnsan düşünebilen, hareket edebilen bir organizmadır” demenin yolu aşağıdaki kod parçasıdır:

Çok Biçimlilik (Polymorphism)

Aşağıdaki kod parçasında görüleceği gibi aynı metota çağrı yapıyormuşuz gibi görünüyor fakat iki farklı aksiyon yürütülüyor.

foreach (var movable in new IMovable[]{new Rover(), new Human()})
{
movable.GoForward();
}

Çıktı şu şekilde olacaktır:

Tekerlek döndürülüyor
Adım atılıyor

Kapsülleme (Encapsulation)

Rover sınıfına bakacak olursak, bu sınıfa ait bir örnek oluşturulurken nesnenin ilk anda bulunduğu nokta ve baktığı yön bilgisi alınmaktadır. Ardından nesneye GoForward (ileri git) veya Turn (dön) emirleri metotlar aracılığı ile iletilmektedir. Bu metotlar aracılığı ile Rover sınıfının bulunduğu noktanın değeri değiştirilmektedir. Kullanıcı matematik işlemleri ile uğraşmak zorunda kalmaz. Kullanım senaryosu aşağıdaki gibi basit olur, buna karşın karmaşıklık Rover sınıfının içerisinde gizlenir.

Karmaşıklığın gizlenmesi dışında, özelliklere erişimin kısıtlanması da kapsülleme olarak isimlendirilir. Kısıtlama işlemleri için kullanılan anahtar kelimelere erişim belirteci (access modifiers) denir.

  • public: bu etiket ile etiketlenen metot, alan veya özelliğe herkesin erişebileceğini anlatır.
  • protected: bu etiket ile etiketlenen metot, alan veya özelliğe sınıfın kendisinin ve bu sınıftan türemiş sınıfların erişebileceğini anlatır.
  • private: bu etiket ile etiketlenen metot, alan veya özelliğe sınıfın kendisinden başka kimsenin erişemeyeceğini anlatır.
  • internal: bu etiket ile etiketlenen metot, alan veya özelliğe aynı assembly içerişindeki sınıflar tarafından erişilebileceğini anlatır.

Rover sınıfının içerisinde `public Point CurrentPoint { get; private set; }` şeklinde bir satır görmekteyiz. CurrentPoint özelliğine erişimlerin public get ve private set oluşu şu anlama gelmektedir: bir aracın (rover) o anki konumunu okuyabilirsiniz ama değiştiremezsiniz. Değiştirmek için GoForward metodunu kullanmamız gerekecektir.

var rover = new Rover();
rover.Turn(RelativeDirections.Left);
Console.Writeline(rover.CurrentPoint);
Console.Writeline(rover.Facade);

Rover sınıfı

MarsRover sorunun çözümü sırasında SOLID prensiplerine uymak için yapılmış hamlelerin anlatıldığı yazıya bu link aracılığı ile erişebilirsiniz. Umarım faydalı bir yazı olmuştur. Herkese iyi günler dilerim.

var software = ConvertFrom(caffeine)

Love podcasts or audiobooks? Learn on the go with our new app.