Ana içeriğe geç

Observer Pattern

Observer deseni, nesneler arasında bire-çok bağımlılık kurarak olay tabanlı iletişim sağlar; yanlış kullanımlar bellek sızıntısı ve sıkı bağımlılık sorunlarına yol açar.


1. Event Handler ile Bellek Sızıntısı

Yanlış Kullanım: Event handler’ları unsubscribe etmemek.

public class OrderPage
{
    public OrderPage(OrderService service)
    {
        service.OrderCompleted += OnOrderCompleted; // Unsubscribe yapılmıyor
    }

    private void OnOrderCompleted(object sender, OrderEventArgs e)
    {
        // UI güncelle
    }
}

İdeal Kullanım: IDisposable ile event handler’ı temizleyin.

public class OrderPage : IDisposable
{
    private readonly OrderService _service;

    public OrderPage(OrderService service)
    {
        _service = service;
        _service.OrderCompleted += OnOrderCompleted;
    }

    private void OnOrderCompleted(object sender, OrderEventArgs e)
    {
        // UI güncelle
    }

    public void Dispose()
    {
        _service.OrderCompleted -= OnOrderCompleted;
    }
}

2. Sıkı Bağımlı Observer Yapısı

Yanlış Kullanım: Observer’ı concrete sınıfa bağlamak.

public class StockService
{
    private readonly EmailService _emailService;
    private readonly SmsService _smsService;

    public void UpdatePrice(decimal price)
    {
        _emailService.Send($"Yeni fiyat: {price}");
        _smsService.Send($"Yeni fiyat: {price}");
    }
}

İdeal Kullanım: Interface tabanlı observer listesi ile gevşek bağlılık sağlayın.

public interface IPriceObserver
{
    Task OnPriceChanged(decimal newPrice);
}

public class StockService
{
    private readonly IEnumerable<IPriceObserver> _observers;

    public StockService(IEnumerable<IPriceObserver> observers)
    {
        _observers = observers;
    }

    public async Task UpdatePrice(decimal price)
    {
        foreach (var observer in _observers)
            await observer.OnPriceChanged(price);
    }
}

3. MediatR Notification Kullanmamak

Yanlış Kullanım: Manuel event dispatch mekanizması yazmak.

public class OrderService
{
    private readonly List<Action<Order>> _handlers = new();

    public void Subscribe(Action<Order> handler) => _handlers.Add(handler);

    public void Complete(Order order)
    {
        // İş mantığı
        foreach (var handler in _handlers)
            handler(order);
    }
}

İdeal Kullanım: MediatR Notification ile event yayınlayın.

public record OrderCompletedEvent(Order Order) : INotification;

public class OrderService
{
    private readonly IMediator _mediator;

    public OrderService(IMediator mediator) => _mediator = mediator;

    public async Task Complete(Order order)
    {
        // İş mantığı
        await _mediator.Publish(new OrderCompletedEvent(order));
    }
}

public class SendEmailHandler : INotificationHandler<OrderCompletedEvent>
{
    public Task Handle(OrderCompletedEvent notification, CancellationToken ct)
    {
        // E-posta gönder
        return Task.CompletedTask;
    }
}

4. Senkron Observer ile Performans Sorunu

Yanlış Kullanım: Tüm observer’ları senkron çalıştırmak.

public void Notify(OrderEvent orderEvent)
{
    foreach (var observer in _observers)
    {
        observer.Handle(orderEvent); // Uzun süren observer tüm zinciri bloklar
    }
}

İdeal Kullanım: Asenkron ve paralel çalıştırın.

public async Task NotifyAsync(OrderEvent orderEvent)
{
    var tasks = _observers.Select(o => o.HandleAsync(orderEvent));
    await Task.WhenAll(tasks);
}

5. Observer’da Exception Yönetimi

Yanlış Kullanım: Bir observer’ın hatası tüm zinciri kırmak.

public async Task NotifyAsync(OrderEvent orderEvent)
{
    foreach (var observer in _observers)
    {
        await observer.HandleAsync(orderEvent); // Birisi hata fırlatırsa geri kalanı çalışmaz
    }
}

İdeal Kullanım: Her observer’ı izole ederek hata yönetimi yapın.

public async Task NotifyAsync(OrderEvent orderEvent)
{
    foreach (var observer in _observers)
    {
        try
        {
            await observer.HandleAsync(orderEvent);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "{Observer} işlenirken hata oluştu", observer.GetType().Name);
        }
    }
}