Arkadaşlar, bugün size programlamanın bel kemiği diyebileceğimiz iki temel kavramdan bahsedeceğim: Class ve Object. Hani şu her yerde karşımıza çıkan, \”OOP nedir?\” diye sorduğumuzda ilk akla gelenler var ya, işte onlardan… Açıkçası ben bu işlere ilk başladığımda bu kavramlar bana biraz yabancı gelmişti, sanki havada kalıyor gibiydiler. Ama zamanla, özellikle C# ve .NET dünyasına adım attıkça, bu iki kelimenin aslında ne kadar hayat kurtarıcı olduğunu anladım.
Şimdi düşünün, bir araba tasarlayacaksınız. Bu arabayı tasarlarken önce bir \”blueprint\” yani bir plan çizmeniz gerekir, değil mi? Bu planda arabanın rengi ne olacak, kaç kapısı olacak, motoru nasıl çalışacak, direksiyonu nerede duracak… Bütün bu detaylar o planda tanımlanır. İşte bu plan, bizim dünyamızda Class dediğimiz şeyin ta kendisi. Class, bir nesnenin neye benzeyeceğini, hangi özelliklere sahip olacağını ve neler yapabileceğini belirleyen bir şablondur aslında.
Peki, bu şablondan gerçeğe nasıl döküyoruz? İşte tam burada Object (Nesne) devreye giriyor. Arabanın planını çıkardık ya, şimdi o plandan yola çıkarak gerçek bir araba üretiyoruz. Bu ürettiğimiz gerçek araba, artık bir nesnedir. Kendi rengi var, kendi plakası var, kendi motor sesi var. Hatta yolda giderken korna çalabilir, farlarını yakabilir. İşte bu ürettiğimiz her bir araba, birer Object’tir. Yani Class dediğimiz şablondan üretilmiş somut varlıklar.
Bu mantığı biraz daha somutlaştırmak istersek, şöyle düşünelim: Bir \”Kullanıcı\” Class’ı tanımladınız diyelim. Bu Class’ın içinde kullanıcının adı, soyadı, e-posta adresi gibi özellikleri olabilir. Bir de \”Giriş Yap\” veya \”Şifre Değiştir\” gibi metotları (yani yapabileceği eylemler) olabilir. Sonra bu \”Kullanıcı\” Class’ından yola çıkarak, her biri farklı bilgilere sahip birden çok kullanıcı nesnesi üretebilirsiniz. Mesela, benim kullanıcı nesnemin adı \”Ali\”, e-posta adresim \”ali@email.com\” olabilir. Sizinki de farklı bilgilerle \”Veli\” olabilir. İşte bu Ali ve Veli, bizim User Class’ımızın Object’leridir.
Neden peki bu Class ve Object kavramı bu kadar önemli? Aslında olay şurada yatıyor: Programlarımızı daha düzenli, daha yönetilebilir ve daha tekrar kullanılabilir hale getiriyorlar. Hani şu büyük projelerde kodun birbiriyle nasıl entegre olacağını düşünürken içimiz bayılır ya, işte Class ve Object mantığı sayesinde bu karmaşıklık çok ciddi oranda azalıyor. Kendi yazdığınız bir Class’ı, projenizin farklı yerlerinde hatta başka projelerinizde bile rahatlıkla kullanabiliyorsunuz. Bu da zaman kazandırıyor ve hata yapma olasılığını azaltıyor. Tabi, ilk başta biraz kafa karıştırıcı gelebilir, yani bu soyut kavramları somutlaştırmak zaman alabilir.
Şimdi gelelim işin en can alıcı kısmına, yani kod örneğine. Diyelim ki basit bir `Urun` (Ürün) Class’ı oluşturmak istiyoruz. Bu ürünün bir adı, bir fiyatı ve bir de stok adedi olacak. Hatta bir de \”StokGuncelle\” metodu olsun ki, stok miktarını değiştirebilelim. İlk bakışta bunu nasıl yaparız diye düşünebiliriz, ama aslında oldukça basit. Hani derler ya, \”basit bir proxy programıydı kendileri\” gibi, bu da öyle basit bir başlangıç aslında.
Önce Class’ımızı tanımlıyoruz. Bu Class’ın içinde `Adi`, `Fiyati` ve `StokAdedi` adında özelliklerimiz (properties) olacak. Ardından `StokGuncelle` adında bir metodumuz olacak. Bu metod, yeni stok adedini alıp mevcut stok adedini güncelleyecek. Sonrasında da bu Class’tan yola çıkarak somut ürün nesneleri oluşturacağız.
Şimdi, ilk yaptığımız şey şöyle bir şey olabilir (tabii ki bu doğru ama daha iyi bir yolu var):
// YANLIŞ YAKLAŞIM (Daha az optimize)
public class Urun { public string Adi { get; set; } public decimal Fiyati { get; set; } public int StokAdedi { get; set; } public void StokGuncelle(int yeniStok) { this.StokAdedi = yeniStok; } }
Bu kod gayet güzel çalışıyor, evet. Ama hani şu C# ve .NET dünyasında sıkça duyduğumuz `record` türlerini düşününce, işler biraz daha farklılaşıyor. `record` türleri, özellikle veri taşıyan nesneler için daha pratik bir çözüm sunuyor. Immutable (değiştirilemez) olmaları ve otomatik olarak `Equals`, `GetHashCode` gibi metodları implement etmeleri sayesinde kodumuz daha temiz ve güvenli hale geliyor.
Yani, yukarıdaki kodu `record` kullanarak şöyle daha da güzelleştirebiliriz:
// DOĞRU YAKLAŞIM (record ile daha temiz)
public record UrunRecord(string Adi, decimal Fiyati, int StokAdedi) { public void StokGuncelle(int yeniStok) { // Record'lar immutable olduğu için doğrudan 'this.StokAdedi = yeniStok' yapamayız. // Bunun yerine, yeni bir nesne döndürebiliriz veya farklı bir metotla yönetebiliriz. // Basit bir örnek için, burada doğrudan atama yapamıyoruz ama bu Record'un mantığıdır. // Gerçek kullanımda, yeni bir nesne oluşturmak veya farklı bir desen kullanmak daha doğru olur. // Ancak temel mantığı anlamak için bu örnek yeterli sanırım. Console.WriteLine($"Ürün '{Adi}' için stok {StokAdedi}'den {yeniStok} olarak güncellendi (Yeni nesne oluşturulacak)."); } }
Burada gördüğünüz gibi `record` kullandık. `record`’lar otomatik olarak constructor’larını oluşturuyor ve özelliklerini daha sade bir şekilde tanımlamamızı sağlıyor. Ancak bir noktaya dikkat etmek lazım: `record`’lar varsayılan olarak immutable’dır. Yani bir kere oluşturulduktan sonra içindeki değerleri doğrudan değiştiremezsiniz. Eğer bir değeri güncellemek isterseniz, aslında yeni bir `record` nesnesi oluşturmanız gerekir. Bu, veri bütünlüğünü sağlamak açısından harika bir özellik. Tam hatırlamıyorum ama bu yüzden özellikle veri modellerinde çok kullanışlı oluyorlar.
Şimdi gelelim bu `UrunRecord`’dan nasıl bir nesne üreteceğimize:
// Nesne Oluşturma ve Kullanım
var urun1 = new UrunRecord("Laptop", 15000.50m, 50); var urun2 = new UrunRecord("Mouse", 250.75m, 100);Console.WriteLine($"Ürün: {urun1.Adi}, Fiyat: {urun1.Fiyati}, Stok: {urun1.StokAdedi}"); urun1.StokGuncelle(45); // Yeni bir nesne oluşturulup atanması gerekir. Bu sadece bir gösterim. Console.WriteLine($"Güncellenmiş (yeni nesne) stok: {urun1.StokAdedi}"); // Bu satır hata verir, çünkü doğrudan güncellenemez. // Doğru kullanım: var guncelUrun1 = urun1 with { StokAdedi = 45 }; // Console.WriteLine($"Güncellenmiş (yeni nesne) stok: {guncelUrun1.StokAdedi}");
Gördüğünüz gibi, `record` kullanmak kodu daha okunabilir ve yönetilebilir hale getiriyor. Bu arada, bu `record` mantığını anlamak için biraz araştırma yapmak gerekebilir, zira başlangıçta diğer türlerden farklı gelebilir. Nesne yönelimli programlamanın temelinde yatan bu Class ve Object mantığı, yazılım geliştirme sürecinde bize inanılmaz bir esneklik ve güç katıyor. Neticede, bu kavramları iyi öğrenmek, daha kaliteli ve sürdürülebilir uygulamalar geliştirmemizin önünü açıyor.
Eğer bu konuyu daha derinlemesine incelemek isterseniz, Microsoft’un kendi dokümantasyonlarına göz atabilirsiniz. Genellikle C# Class’ları hakkında veya C# Record türleri hakkında yapılan aramalar sizi doğru yerlere götürecektir. Hatta YouTube’da da bu konuda birçok eğitici video bulabilirsiniz, bu linke bir bakabilirsiniz sanırım.
Sonuç olarak, Class’lar bizim şablonlarımız, Object’ler ise bu şablonlardan ürettiğimiz somut varlıklar. Bu iki kavramı iyi anlamak ve doğru yerlerde kullanmak, kodunuzun kalitesini artıracaktır. Ne güzel değil mi? Bir sonraki yazıda görüşmek üzere, kendinize iyi bakın!