Giriş

Modern yazılım geliştirmede immutable pattern, güvenli ve sürdürülebilir kod yazmanın temel taşlarından biridir. Bu pattern, nesne oluşturulduktan sonra durumunun değiştirilemez olmasını sağlar.

immutable_object

Immutable nesneler, özellikle çok iş parçacıklı uygulamalarda kritik öneme sahiptir. Thread safety sorunlarını ortadan kaldırırken, kodun öngörülebilirliğini artırır.

Bu rehberde, immutable object pattern‘inin C# ile nasıl uygulanacağını öğreneceksiniz. Temel kavramlardan başlayarak, ileri seviye tekniklere kadar kapsamlı bir bakış açısı sunacağız.

Temel Bilgiler

Immutable Nedir?

Immutable, Türkçe karşılığı “değişmez” olan bir kavramdır. Bir nesne immutable olduğunda, oluşturulduktan sonra iç durumu hiçbir şekilde değiştirilemez.

Temel Özellikler

Immutable pattern‘in temel özellikleri şunlardır:

  • Nesne oluşturulduktan sonra değiştirilemez
  • Tüm alanlar readonly veya private olmalıdır
  • Setter metodları bulunmaz
  • Thread-safe yapıdadır

Basit Immutable Sınıf Örneği

public class Person
{
    public string Name { get; }
    public int Age { get; }
    
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
}

Bu örnekte Person sınıfı immutable‘dır. Özellikler sadece constructor ile atanabilir ve sonrasında değiştirilemez.

Avantajları

Immutable pattern kullanmanın başlıca avantajları:

  • Thread Safety: Çoklu iş parçacığında güvenli kullanım
  • Öngörülebilirlik: Nesne durumu sabit kalır
  • Hashing: Dictionary ve HashSet kullanımında güvenli
  • Debugging: Hata ayıklama sürecinde kolaylık

Orta Seviye Detaylar

Derin Immutability

Pattern‘in doğru uygulanması için sadece primitive tipler yeterli değildir. Referans tipleri de immutable olmalıdır.

public class Address
{
    public string City { get; }
    public string Country { get; }
    
    public Address(string city, string country)
    {
        City = city;
        Country = country;
    }
}

public class Employee
{
    public string Name { get; }
    public Address WorkAddress { get; }
    
    public Employee(string name, Address address)
    {
        Name = name;
        WorkAddress = address; // Address de immutable olmalı
    }
}

Collection’lar ile Çalışma

Immutable nesnelerde koleksiyonlar özel dikkat gerektirir:

public class Department
{
    private readonly List<string> _employees;
    
    public IReadOnlyList<string> Employees => _employees.AsReadOnly();
    
    public Department(IEnumerable<string> employees)
    {
        _employees = employees.ToList();
    }
}

Builder Pattern ile Kombinasyon

Karmaşık immutable nesneler için Builder pattern kullanılabilir:

public class Product
{
    public string Name { get; }
    public decimal Price { get; }
    public string Category { get; }
    
    private Product(string name, decimal price, string category)
    {
        Name = name;
        Price = price;
        Category = category;
    }
    
    public class Builder
    {
        private string _name;
        private decimal _price;
        private string _category;
        
        public Builder SetName(string name)
        {
            _name = name;
            return this;
        }
        
        public Builder SetPrice(decimal price)
        {
            _price = price;
            return this;
        }
        
        public Builder SetCategory(string category)
        {
            _category = category;
            return this;
        }
        
        public Product Build()
        {
            return new Product(_name, _price, _category);
        }
    }
}

Record Types (C# 9.0+)

Modern C# ile immutable pattern uygulaması daha kolaydır:

public record PersonRecord(string Name, int Age);

public record AddressRecord(string City, string Country);

public record EmployeeRecord(string Name, AddressRecord Address);

Record types otomatik olarak immutable yapı sağlar ve pattern uygulamasını basitleştirir.

Structural Equality

Immutable nesnelerde değer karşılaştırması önemlidir:

public class ValueObject
{
    public string Value { get; }
    
    public ValueObject(string value)
    {
        Value = value;
    }
    
    public override bool Equals(object obj)
    {
        if (obj is ValueObject other)
            return Value == other.Value;
        return false;
    }
    
    public override int GetHashCode()
    {
        return Value?.GetHashCode() ?? 0;
    }
}

Performance Optimizasyonları

Immutable pattern kullanırken performans için dikkat edilmesi gerekenler:

  • String Interning: Tekrarlanan string değerler için
  • Lazy Loading: Hesaplanan özellikler için
  • Caching: Pahalı işlemler için
public class OptimizedImmutable
{
    private readonly Lazy<string> _expensiveValue;
    
    public string ExpensiveValue => _expensiveValue.Value;
    
    public OptimizedImmutable(string input)
    {
        _expensiveValue = new Lazy<string>(() => 
            ComputeExpensiveOperation(input));
    }
    
    private string ComputeExpensiveOperation(string input)
    {
        // Pahalı işlem
        return input.ToUpper();
    }
}

Functional Programming Entegrasyonu

Immutable pattern, fonksiyonel programlama yaklaşımları ile uyumludur:

public static class ImmutableExtensions
{
    public static Person WithName(this Person person, string newName)
    {
        return new Person(newName, person.Age);
    }
    
    public static Person WithAge(this Person person, int newAge)
    {
        return new Person(person.Name, newAge);
    }
}

// Kullanım
var originalPerson = new Person("Ahmet", 30);
var updatedPerson = originalPerson.WithAge(31);

Sonuç

  • Immutable object pattern, modern C# geliştirmede vazgeçilmez bir pattern‘dir. Kod güvenliğini artırırken, hata potansiyelini azaltır.
  • Bu pattern‘in doğru uygulanması, özellikle çok iş parçacıklı uygulamalarda kritik öneme sahiptir. Record types ile birlikte, C#’da immutable nesne oluşturma süreci oldukça basitleşmiştir.
  • Immutable pattern kullanırken, performans ve bellek yönetimi konularını da göz önünde bulundurmak önemlidir. Lazy loading ve caching teknikleri ile optimize edilmiş çözümler geliştirilebilir.
  • Son olarak, immutable yaklaşımı benimserken, projenizin gereksinimlerini değerlendirmeyi unutmayın. Her durumda immutable pattern uygun olmayabilir, ancak çoğu senaryoda güvenli ve sürdürülebilir kod yazmanıza yardımcı olacaktır.

Kaynakça

By tanju.bozok

Software Architect, Developer, and Entrepreneur

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir