Nesne Yönelimli Programlama, en basit anlatımıyla gerçek hayatı uygulama düzeyinde modellememizi sağlayan yaklaşımdır.

Bu prensipler birçok yerde kopyala-yapıştır bir dil kullanılarak havada kalan açıklamalar ile anlatılıyor. Ben bunun aksine gerçek hayattan örneklerle aynı zamanda koda da dökerek C# ile anlatmaya çalışacağım; mantık OOP olan her dil için zaten birebir aynıdır. Her prensip için kısa kod blokları ve sonunda bunları birleştirierek küçük bir projede toplamayı planlıyorum. Temelde dört ana prensibi olduğu varsayılır.

  • Encapsulation
  • Inheritance
  • Abstraction
  • Polymorphism

İlki ile başlayalım. İlk temel prensibimiz Encapsulation, yani Kapsülleme; teknik anlamından öte en anlaşılır şekliyle sınıf içindeki üyelerin olası bir yanlış kullanımdan etkilenmemesi gerektiğini ele alan prensiptir. "Tamam ama olası yanlış kullanım nedir?" derseniz uygulamayı kullananlar değil geliştirme aşamasındaki yanlış kullanımlardan korumaktır amacımız. Accessor ya da property seviyelerinde kullanılır. Üyeyi niteleyen public, private, protected, internal erişim belirleyicileri ile veya read-only(sadece okunablir), write-only(sadece yazılabilir) kullanım şekilleri vardır. Kabaca ne olduklarını belirtirsek:

public"Halka açık, herkes kullanabilir"  gibi anlamlara gelir. İşaretlediği üyeye diğer tüm sınıflardan erişilebilir.
private"Özel" anlamına gelir. İşaretlediği üyeye diğer sınıflardan değil sadece dahil olduğu sınıftan erişilebilir.
protected"Korumalı" anlamına gelir. Diğer bir OOP prensibi olan Inhertance(Kalıtım) ile doğrudan igilidir. İşaretlediği üyeye diğer sınıflardan erişilemez, sadece dahil olduğu sınıftan ve miras verdiği sınıflardan erişilebilir.
internal"Dahili, içe ait, içsel" gibi anlamları vardır. İşaretlediği üyeye sadece dahil olduğu projeden erişilebilir.

Bunlar kesinlikle bilinmesi gereken teorik bilgiler. Şimdi pratikte bunları küçük kod örneklerine dökelim; gerçek hayattan aklıma gelen örnekler aşağıda.

Bununla ilgili anlaşılması en kolay örnek bir kişinin yaşı olduğunu düşünüyorum. Yaşımızı kendimiz belirleyemeyiz; tabi eğer ışıktan ⚡ hızlı gitmiyorsak.😄Herkesin kesin ve net olarak tek bir doğum tarihi vardır; yaşımız buna göre her yıl değişir. Yani yaş, doğum tarihine sıkı bir şekilde bağlıdır. Siz eğer yaşı her yerden ya da herkes atayabilecek şekilde yazarsanız uygulamanın bir yerinde başka bir geliştirici de bir gün ona herhangi bir yaşı atabilir. Aslında ideal olanı yaş için bir constrasion tanımlamaktır ama gerçek hayat böyle değil, yaşın sonradan belli yetkiler dahilinde atanmasını doğurabilecek durumlar olabiliyor.

Başka örnekler, ek hesap falan gibi ekstralarını bir kenara bırakırsak; vadesiz hesapta nakit olmadıkça para çektirmezsiniz. Bir gelir için eksi değer girdirmezsiniz; eğer değer negatifse ayrı bir uyarı verip girdirebilirsiniz. Bir öğrenciye 0'dan düşük not verdirmeyebilirsiniz, gibi gibi...

Bu prensibin, korumadan başka dolaylı bir amacı da karmaşık üyeleri izole bir şekilde ayrıştırarak nasıl çalıştıklarından bağımsız kullanılır olmalarını sağlamaktır. Arabanızı kullanabilmeniz için motorunun tüm özelliklerini ya da vitesin şanzımandaki mekanik hareketlerini bilmek zorunda değilsiniz. Ama sonuçta o motorun tasarımını, geliştirmesini ve testlerini birileri yaparak en iyi verimle seri üretime geçmiştir. Her markanın böyle düzgün çalışmadığını ben de biliyorum ama ana fikri kaçırmayalım, kuvvet-hareket-ivme-momentum-iş gibi kavramları bilmeden de aracı kullanırsınız. Debriyaj diye bildiğimiz bir pedalla baskı ve volanı ayırıp vites diye bildiğimiz uyduruk bir kolla altımızdaki bir sürü dişliyi kontol eder, bunu tasarlayan adamlar dururken "Ne kadar hızlı vites değiştiriyorum" falan diye bir de bunun havasını atarız.🤭

Şu an bu yazıyı okuduğunuz ekran; bir bilgisayar, telefon, tv her neyse onu çalıştıran iç yapısı sizi ilgilendirmemeli ki siz bunları dert etmeden kullanabilesiniz. Hız, performans benzeri kriterlerden bahsetmiyorum o zaman ilgilendirebilir, ama sadece ilgilendirir, inceler ona göre bir marka, model falan seçersiniz. Oturup evde bir işlemci ya da ne bileyim bir SSD disk imal edeyim gibi tuhaf bir istek içine girmezsiniz.

Bunlar gerçek hayattan rastgele bulduğum küçük örnekler. Normalde bunlar bir sürü kontrolün yapıldığı çok daha karmaşık operasyonlar tabi ama en basitleştirilmiş kod örnekleri aşağıda. Yalnız bastileştirilmiş olduğuna özellikle dikkat edin, çünkü class içinde Console kullanımı da bir bağımlılıktır ve OOP'e ters bir yaklaşımdır. Ancak bunun çözümü oop ilkelerini öğrenme seviyesi için fazla kafa karıştırıcı olacağından bunu göz ardı edip direk konsol arayüz kullanıyoruz. Console satırları yerine hataları tutan basit bir property olduğunu da farzedebilirsiniz.

namespace GurkanTuna.Encapsulation {
	
	class Employee {
        public Employee(string firstName, string lastName, DateTime birthDate) {
            this.FirstName = firstName;
            this.LastName = lastName;
            this.BirthDate = birthDate;
            this.DateOfRecruitment = DateTime.Now;
            Console.WriteLine($"{FirstName} {LastName} ({Age}) {DateOfRecruitment:F} işe başladı.");
        }
		public string FirstName { get; set; }
        public string LastName { get; set; }

        public DateTime DateOfRecruitment { get; private set; }

        public DateTime BirthDate { get; protected set; }
        public int Age => DateTime.Now.Year - BirthDate.Year;
    }	
	
	class Account {
		public decimal Balance { get; set; }
		
		public bool Withdraw(decimal amount) {
            var result = false;
            if (Balance <= 0) {
                Console.WriteLine($"Hesabınızda {Balance} bakiye bulunmaktadır.\n{amount} TL çekebilmek için hesabınıza en az " +
                                  $"{Balance * -1 + amount} TL yatırmanız gerekmektedir.");
            }
            else if (amount > Balance) {
                Console.WriteLine("Hesabınızda yeterli miktar bulunamadı!");
            }
            else {
                Balance -= amount;
                result = true;
            }
            return result;
        }
	}
	
   class VehicleBase {
        private readonly int _maxGear = 5;
        public int Gear { get; private set; }

        public double Speed { get; set; }

        public virtual int GearShift(int gear) {
/*
Burada manuel vites değiştiriyoruz. Vites değiştirme aralıkları, kaç milisaniyede 
olacak falan gibi yüzlerce parametreye bakıp ona göre karar verirsiniz. Eğer manuel doğru vites seçilmiyorsa izin vermezsiniz. Yani güçlü bir motorumuz var ve 150 km/sa ile 3'e atarsak izin veriyor 151 ile vermiyor gibi.
*/
            if (gear == 3 && Speed >= 40 && Speed <= 150) {
                Gear = gear;
            }
            return Gear;
        }

        public virtual int GearUp() {
            if (Gear != _maxGear) {
                ++Gear;
            }
            return Gear;
        }

        public virtual int GearDown() {
            if (Gear > 0) {
                --Gear;
            }
            return Gear;
        }
    }

    class Car : VehicleBase {
        public override int GearShift(int gear) {
            /*
            Aslında burada hiçbirşey yapmanıza gerek yok ama mesela o markaya
            ya da modele özel yapmak istediğiniz ayarlar varsa burada girersiniz.
            */
            return base.GearShift(gear);
        }
    }
}

Nesne Yönelimli Programlama (OOP) Temel Prensipleri 2 - Inheritance