OOP'ye Giriş: Neden Prosedürel Programlama Artık Yetmiyor?
Son güncelleme:
4 dk okuma

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; Microsoft'un C#'ta nesne yönelimli programlama belgesi de bu prensipleri class, struct ve record üzerinden anlatıyor. 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. Bunu sağlayan araçları access modifiers yazısında tek tek inceliyoruz.
2. Inheritance (Kalıtım)
Kod tekrarından kurtulmak. VadeliHesap ve VadesizHesap sınıfları, BankaHesabi'ndan ortak özellikleri miras alabilir. virtual, override ve base ile bunun nasıl kurulduğunu kalıtım ve polymorphism rehberinde anlattım.
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. C#'ta soyutlamanın iki aracı var; hangisini ne zaman seçeceğinizi interface ve abstract class farkı yazısında karşılaştırdım.
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; dilin tamamını Microsoft'un resmî C# kılavuzundan takip edebilirsiniz. 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. Bu temelleri bir eğitmenle çalışmak istiyorsanız .NET uzmanı öğretmen seçerken hangi ölçütlere bakmalı yazısı seçim kriterlerini bir arada topluyor.
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.
Sık Sorulan Sorular
OOP öğrenmeden önce prosedürel programlama bilmek gerekir mi?
Evet, değişken, döngü, koşul ve metod gibi temelleri bilmeniz gerekir. OOP bu temelleri ortadan kaldırmaz; onları sınıflar içinde nasıl organize edeceğinizi söyler.
C#'ta her şey bir class içinde mi olmak zorunda?
Görünürde hayır: top-level statements sayesinde Program.cs içine doğrudan kod yazabilirsiniz, derleyici onu arka planda bir sınıfa sarar. Kendi tiplerinizi tanımlamak istediğinizde ise class, struct veya record kullanırsınız.
struct ve record varken neden class ile başlıyoruz?
class referans tipidir, kalıtımı destekler ve OOP'nin dört prensibinin tamamını gösterebildiğimiz tek yapıdır. struct küçük değer tipleri, record ise veri taşıyan değişmez nesneler için tercih edilir; ikisini de class mantığı oturduktan sonra öğrenmek çok daha kolay.
İlgili Yazılar
C# Constructor: Nesne Fabrikasının Gizli Kahramanı
Constructor nedir, neden gerekli? Default constructor, parametreli constructor ve constructor overloading kavramlarını gerçek dünya örnekleriyle keşfediyoruz.
C# Class ve Object: Taslak mı, Ürün mü?
OOP'nin temel yapı taşları Class ve Object'i kek kalıbı analojisiyle öğrenin. Property, Method ve Instance kavramları örneklerle.
C# Access Modifiers: Kapıları Kilitlemek mi, Açık Bırakmak mı?
public, private, protected ve internal nedir? Getter/Setter metodlarıyla veri güvenliğini banka hesabı örneğiyle anlatıyorum.