Ahmet Balaman LogoAhmet Balaman

OOP'ye Giriş: Neden Prosedürel Programlama Artık Yetmiyor?

personAhmet Balaman
calendar_today
C#OOPNesne Yönelimli Programlama.NETProgramlama Temelleri

OOP'ye Giriş: Kod Yazarken Bir Şeyler Yanlış Gidiyordu

Yıllar önce ilk programlama deneyimim şuydu: Yukarıdan aşağıya, satır satır kod yazmak. Değişken tanımla, fonksiyon yaz, çağır, sonucu al. Basit ve anlaşılır görünüyordu. Ta ki projeler büyümeye başlayana kadar.

Bir gün kendimi 2000 satırlık tek bir dosyanın içinde kaybolmuş buldum. "Bu fonksiyon hangisini çağırıyordu?", "Bu değişkeni kim değiştirdi?" sorularıyla boğuşurken fark ettim: Bir şeyler yanlış gidiyordu.

Prosedürel Programlama: İyi Başladık Ama...

Prosedürel programlama aslında mantıklı bir yaklaşım. Bir yemek tarifi gibi düşünün:

// Prosedürel yaklaşım - Basit hesap makinesi
double bakiye = 1000;

void ParaYatir(double miktar)
{
    bakiye += miktar;
    Console.WriteLine($"Yatırılan: {miktar} TL, Yeni bakiye: {bakiye} TL");
}

void ParaCek(double miktar)
{
    if (bakiye >= miktar)
    {
        bakiye -= miktar;
        Console.WriteLine($"Çekilen: {miktar} TL, Yeni bakiye: {bakiye} TL");
    }
    else
    {
        Console.WriteLine("Yetersiz bakiye!");
    }
}

// Kullanım
ParaYatir(500);
ParaCek(200);

Güzel, çalışıyor. Peki ya şimdi birden fazla hesap olsaydı? Ya her hesabın farklı özellikleri olsaydı? Kredi hesabı, vadeli hesap, döviz hesabı...

İşte tam bu noktada prosedürel yaklaşım çatırdamaya başlıyor.

Spaghetti Kod: Herkesin Başına Gelen Kabus

Prosedürel kodun en büyük problemi: Her şey birbirine bağlı. Bir yeri değiştirdin mi, başka bir yer patlıyor. Buna "spaghetti kod" diyoruz. Spagetti tabağına baktığınızda hangi makarna nereye gidiyor anlayabilir misiniz? İşte kod da öyle oluyor.

// Spaghetti kod örneği - Gerçek hayattan kaçınılması gereken kod
string hesap1_sahibi = "Ahmet";
double hesap1_bakiye = 1000;
string hesap1_tip = "vadesiz";

string hesap2_sahibi = "Mehmet";
double hesap2_bakiye = 5000;
string hesap2_tip = "vadeli";

string hesap3_sahibi = "Ayşe";
double hesap3_bakiye = 2500;
string hesap3_tip = "döviz";

// Para transferi? Hangisi hangisine? Hangi değişkeni kullanacağız?
// Yeni hesap eklersek? hesap4, hesap5, hesap6...
// 100 hesap olursa? 🤯

Bu kod büyüdükçe yönetilemez hale geliyor. Her yeni özellik eklediğimizde karmaşıklık katlanarak artıyor.

Gerçek Dünya Böyle Çalışmıyor

Bir dakika durup düşünelim. Gerçek dünyada nesneler var:

  • Araba: Rengi var, hızı var, markası var. Çalıştırılabilir, durdurulabilir.
  • Banka Hesabı: Sahibi var, bakiyesi var. Para yatırılabilir, çekilebilir.
  • Telefon: Modeli var, şarj durumu var. Aranabilir, mesaj gönderilebilir.

Bu nesnelerin özellikleri (property) ve davranışları (method) var. Ve en güzeli: Birbirlerinden bağımsızlar!

Bir arabayı çalıştırmak, başka bir arabayı etkilemiyor. Bir telefona mesaj göndermek, diğerinin şarjını azaltmıyor.

İşte OOP tam olarak bunu yapıyor: Gerçek dünyadaki nesneleri koda çeviriyor.

OOP: Gerçek Dünyayı Koda Taşımak

Nesne Yönelimli Programlama (Object-Oriented Programming) ile aynı banka hesabı örneğini yazalım:

public class BankaHesabi
{
    // Özellikler (Properties)
    public string HesapSahibi { get; set; }
    public double Bakiye { get; private set; }
    public string HesapTipi { get; set; }
    
    // Constructor - Nesne oluşturulurken çağrılır
    public BankaHesabi(string sahip, double baslangicBakiyesi, string tip)
    {
        HesapSahibi = sahip;
        Bakiye = baslangicBakiyesi;
        HesapTipi = tip;
    }
    
    // Davranışlar (Methods)
    public void ParaYatir(double miktar)
    {
        Bakiye += miktar;
        Console.WriteLine($"{HesapSahibi}'nin hesabına {miktar} TL yatırıldı.");
    }
    
    public bool ParaCek(double miktar)
    {
        if (Bakiye >= miktar)
        {
            Bakiye -= miktar;
            Console.WriteLine($"{HesapSahibi}'nin hesabından {miktar} TL çekildi.");
            return true;
        }
        Console.WriteLine("Yetersiz bakiye!");
        return false;
    }
    
    public void BakiyeGoster()
    {
        Console.WriteLine($"{HesapSahibi} - {HesapTipi}: {Bakiye} TL");
    }
}

Şimdi 100 hesap oluşturmak istesek:

// Her hesap kendi verisini ve davranışını taşıyor
BankaHesabi ahmetHesap = new BankaHesabi("Ahmet", 1000, "Vadesiz");
BankaHesabi mehmetHesap = new BankaHesabi("Mehmet", 5000, "Vadeli");
BankaHesabi ayseHesap = new BankaHesabi("Ayşe", 2500, "Döviz");

ahmetHesap.ParaYatir(500);
mehmetHesap.ParaCek(1000);
ayseHesap.BakiyeGoster();

// Ahmet'e yapılan işlem Mehmet'i etkilemiyor!

Ne kadar temiz değil mi? Her hesap kendi evreninde yaşıyor. Birbirlerini etkilemiyorlar.

OOP'nin 4 Temel Prensibi

OOP sadece class yazmak değil. Arkasında 4 temel prensip var. Bunları ilerideki yazılarda detaylı işleyeceğiz, ama şimdilik tanışalım:

1. Encapsulation (Kapsülleme)

Veriyi korumak. Bakiye değişkenini dışarıdan doğrudan değiştirememek. Sadece ParaYatir ve ParaCek metodlarıyla erişebilmek.

2. Inheritance (Kalıtım)

Kod tekrarından kurtulmak. VadeliHesap ve VadesizHesap sınıfları, BankaHesabi'ndan ortak özellikleri miras alabilir.

3. Polymorphism (Çok Biçimlilik)

Aynı metodun farklı davranışlar sergilemesi. ParaCek metodu vadeli hesapta faiz kesintisi yaparken, vadesiz hesapta yapmayabilir.

4. Abstraction (Soyutlama)

Karmaşıklığı gizlemek. Kullanıcı sadece ParaYatir() çağırıyor, arka planda veritabanı işlemleri, log tutma, bildirim gönderme gibi işlemleri bilmesine gerek yok.

Hangi Dillerde OOP Var?

OOP kavramı dil bağımsız. Birçok modern dil OOP destekliyor:

Dil OOP Desteği Notlar
C# ✅ Tam Microsoft'un OOP odaklı dili
Java ✅ Tam "Her şey bir nesne" felsefesi
Python ✅ Tam Dinamik ve esnek OOP
Dart ✅ Tam Flutter'ın dili
Swift ✅ Tam Apple ekosistemi
JavaScript ⚠️ Prototip tabanlı ES6 ile class syntax eklendi
C ❌ Yok Prosedürel dil

Bu blog serisinde C# kullanacağız. Neden mi?

  • Syntax'ı temiz ve okunabilir
  • OOP prensiplerini tam destekliyor
  • IDE desteği mükemmel (Visual Studio, Rider)
  • Gerçek dünya projelerinde yaygın kullanım

Ne Zaman OOP Kullanmalı?

OOP her derde deva değil. Küçük script'ler, basit otomasyon görevleri için prosedürel yeterli olabilir. Ama:

OOP Kullan:

  • Proje büyüyecekse
  • Birden fazla geliştirici çalışacaksa
  • Bakım ve genişletme önemliyse
  • Gerçek dünya nesnelerini modelliyorsan

Prosedürel Yeterli:

  • Tek seferlik script'ler
  • Küçük otomasyon görevleri
  • Performans kritik düşük seviye işlemler

Sonraki Adım: Class ve Object

Bu yazıda OOP'nin neden var olduğunu, prosedürel yaklaşımın sınırlarını ve 4 temel prensibi tanıdık.

Bir sonraki yazıda Class ve Object kavramlarını derinlemesine inceleyeceğiz. "Kek kalıbı vs Kek" analojisiyle bu kavramları somutlaştıracağız.

Kodlarınız temiz, kafanız rahat olsun! 🚀


Bu yazı, C# ile OOP serisinin ilk yazısıdır. Serinin devamında Class, Constructor, Access Modifiers ve daha birçok konuyu ele alacağız.

Yorumlar