Behavioral — Davranışsal Desenler

Observer

Gözlemci (Yayın-Abone) Deseni

Amaç: Bir nesnenin durumu değiştiğinde, ona bağlı (abone olmuş) tüm nesnelerin otomatik olarak haberdar edilmesini sağlamak.

1

Basit Anlatım

Teknik terim yok — günlük hayattan bir benzetme

Bir YouTube kanalına abone olup bildirim zilini açtığınızı düşünün. Kanal yeni bir video yüklediğinde size otomatik olarak bildirim gelir. Siz her gün kanala girip "Yeni video var mı?" diye kontrol etmek zorunda kalmazsınız.

Kanal sahibi de abonelerini tek tek tanımaz. Sadece "Yeni video yayınlandı" der; sistem bunu tüm abonelere iletir. İstediğiniz zaman abonelikten çıkabilirsiniz, kanal bundan etkilenmez.

Gazete aboneliği

Gazeteye abone olursanız her sabah kapınıza gelir. Bayiye gidip sormanıza gerek yoktur. Taşınırsanız ya da istemezseniz aboneliği iptal edersiniz.

Observer şunu der: "Sürekli gelip sorma; bir şey değişince ben sana haber veririm."
2

Teknik Anlamı

Bir yazılımcının bakış açısıyla

Observer, nesneler arasında bire-çok bir bağımlılık tanımlar. Bir nesne (Subject / Publisher) durumu değiştiğinde, kayıtlı tüm Observer / Subscriber nesnelerini bilgilendirir. Subject, observer'ların somut tiplerini bilmez; sadece ortak bir arayüzü bilir.

Katılımcılar

Polling'e karşı Push

Observer olmadan ilgilenen taraflar sürekli "değişti mi?" diye sorar (polling): gereksiz yük ve gecikme. Observer ile değişiklik anında itilir (push).

.NET'te Observer

Avantajlar

Dezavantajlar

3

C# ile Uygulama

Adım adım, çalışan kod örneği

Senaryo: Bir hisse senedi fiyatı değiştiğinde ekran, uyarı servisi ve loglama sistemi haberdar olmalı. Önce klasik arayüz yaklaşımını, sonra C# event ile aynı işi göreceğiz.

Adım 1 Klasik yaklaşım: Observer arayüzü ve Subject

public interface IStockObserver
{
    void Update(string symbol, decimal oldPrice, decimal newPrice);
}

public class Stock
{
    private readonly List<IStockObserver> _observers = new();
    private decimal _price;

    public string Symbol { get; }
    public Stock(string symbol, decimal price) { Symbol = symbol; _price = price; }

    public void Subscribe(IStockObserver o) => _observers.Add(o);
    public void Unsubscribe(IStockObserver o) => _observers.Remove(o);

    public decimal Price
    {
        get => _price;
        set
        {
            if (value == _price) return;
            var old = _price;
            _price = value;
            foreach (var o in _observers) o.Update(Symbol, old, value);  // bildir
        }
    }
}

Adım 2 Somut observer'lar

Her biri aynı bildirime farklı şekilde tepki veriyor.

public class PriceDisplay : IStockObserver
{
    public void Update(string symbol, decimal oldPrice, decimal newPrice) =>
        Console.WriteLine($"  [Ekran] {symbol}: {newPrice:0.00} TL");
}

public class PriceAlert : IStockObserver
{
    private readonly decimal _threshold;
    public PriceAlert(decimal thresholdPercent) => _threshold = thresholdPercent;

    public void Update(string symbol, decimal oldPrice, decimal newPrice)
    {
        var change = (newPrice - oldPrice) / oldPrice * 100;
        if (Math.Abs(change) >= _threshold)
            Console.WriteLine($"  [UYARI] {symbol} %{change:0.0} değişti!");
    }
}

Adım 3 C# usulü: event ile aynı desen

event anahtar kelimesi, abone listesini ve ekleme/çıkarma işlemlerini bizim yerimize yönetir.

public record PriceChangedEventArgs(string Symbol, decimal NewPrice);

public class StockTicker
{
    public event EventHandler<PriceChangedEventArgs>? PriceChanged;

    public void Publish(string symbol, decimal price) =>
        PriceChanged?.Invoke(this, new PriceChangedEventArgs(symbol, price));
}

Adım 4 Kullanım

Tüm parçaları bir araya getiren istemci (client) kodu:

var thy = new Stock("THYAO", 300m);
var display = new PriceDisplay();
thy.Subscribe(display);
thy.Subscribe(new PriceAlert(thresholdPercent: 5));

Console.WriteLine("Fiyat 306 oldu:");
thy.Price = 306m;
Console.WriteLine("Fiyat 330 oldu:");
thy.Price = 330m;

thy.Unsubscribe(display);
Console.WriteLine("Ekran abonelikten çıktı. Fiyat 280 oldu:");
thy.Price = 280m;

Console.WriteLine("\n--- C# event ile ---");
var ticker = new StockTicker();
EventHandler<PriceChangedEventArgs> logger =
    (sender, e) => Console.WriteLine($"  [Log] {e.Symbol} = {e.NewPrice}");
ticker.PriceChanged += logger;                       // abone ol
ticker.Publish("ASELS", 61.75m);
ticker.PriceChanged -= logger;                       // abonelikten çık
ticker.Publish("ASELS", 62.10m);                     // kimse dinlemiyor

Konsol çıktısı

Fiyat 306 oldu:
  [Ekran] THYAO: 306,00 TL
Fiyat 330 oldu:
  [Ekran] THYAO: 330,00 TL
  [UYARI] THYAO %7,8 değişti!
Ekran abonelikten çıktı. Fiyat 280 oldu:
  [UYARI] THYAO %-15,2 değişti!

--- C# event ile ---
  [Log] ASELS = 61,75

Kodda dikkat edilmesi gerekenler

Özetle: Observer, bir nesnedeki değişikliği ona abone olan herkese otomatik olarak duyurur. C#'ta event mekanizması bu desenin ta kendisidir.
← Ana sayfaya dön