Menu
Coddy logo textTech

Observer Kalıbı

Coddy'nin C++ Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 94 / 104.

Observer deseni, nesneler arasında bire-çok bir bağımlılık tanımlar: bir nesne (subject) durum değiştirdiğinde, tüm bağımlıları (observers) otomatik olarak bilgilendirilir. Bu; olay sistemleri, kullanıcı arayüzü (UI) güncellemeleri veya birden fazla nesnenin değişikliklere tepki vermesi gereken her türlü senaryo için idealdir.

Bu desen iki temel rol içerir: gözlemcilerin bir listesini tutan ve onları bilgilendiren bir Subject ve bir güncelleme arayüzü uygulayan Observers:

#include <iostream>
#include <vector>
#include <algorithm>

class Observer {
public:
    virtual void update(int value) = 0;
    virtual ~Observer() = default;
};

class Subject {
    std::vector<Observer*> observers;
    int state = 0;
    
public:
    void attach(Observer* obs) {
        observers.push_back(obs);
    }
    
    void detach(Observer* obs) {
        observers.erase(
            std::remove(observers.begin(), observers.end(), obs),
            observers.end());
    }
    
    void setState(int value) {
        state = value;
        notify();
    }
    
    void notify() {
        for (Observer* obs : observers) {
            obs->update(state);
        }
    }
};

class Display : public Observer {
    std::string name;
public:
    Display(const std::string& n) : name(n) {}
    void update(int value) override {
        std::cout << name << " received: " << value << "\n";
    }
};

int main() {
    Subject sensor;
    Display screen1("Screen1"), screen2("Screen2");
    
    sensor.attach(&screen1);
    sensor.attach(&screen2);
    sensor.setState(42);  // Her iki ekran da bilgilendirildi
}

setState() çağrıldığında, konu (subject) kayıtlı tüm gözlemciler üzerinde döner ve onların update() metodunu çağırır. Gözlemciler herhangi bir zamanda eklenebilir veya ayrılabilir, bu da sistemi esnek ve gevşek bağlı hale getirir.

Bir nesnedeki değişiklikler diğerlerinin güncellenmesini gerektirdiğinde ve bu nesnelerin birbirine sıkı sıkıya bağlı olmasını istemediğinizde Observer desenini kullanın.

challenge icon

Görev

Kolay

Observer desenini kullanarak bir Hava Durumu İstasyonu (Weather Station) izleme sistemi oluşturalım. Sıcaklık verilerini takip eden ve sıcaklık her değiştiğinde birden fazla ekran ünitesini otomatik olarak bilgilendiren bir hava durumu istasyonu oluşturacaksınız; bu, bu desenin gerçek dünyadaki klasik bir uygulamasıdır.

Kodunuzu üç dosya halinde düzenleyeceksiniz:

  • Observer.h: Gözlemci (observer) arayüzünü ve somut bir ekran gözlemcisini tanımlayın.

    Gözlemcilerin bildirimleri almak için uyguladığı saf sanal bir update(double temperature) metoduna ve sanal bir yıkıcıya (destructor) sahip soyut bir Observer sınıfı oluşturun.

    Ardından Observer sınıfından miras alan bir TemperatureDisplay sınıfı oluşturun. Her ekranın yapıcı (constructor) aracılığıyla ayarlanan bir adı (string) vardır. update() çağrıldığında şunu yazdırmalıdır:

    [DisplayName]: Temperature is [temperature] degrees
  • WeatherStation.h: Sıcaklığı tutan ve gözlemcileri bilgilendiren konuyu (subject) oluşturun.

    WeatherStation sınıfınız şunları yapmalıdır:

    • Gözlemci işaretçilerinin (pointers) bir listesini ve mevcut sıcaklığı saklamalıdır (başlangıç değeri 0.0)
    • Gözlemcileri kaydetmek için bir attach(Observer* obs) metoduna sahip olmalıdır
    • Gözlemcileri kaldırmak için bir detach(Observer* obs) metoduna sahip olmalıdır
    • Sıcaklığı güncelleyen ve tüm bağlı gözlemcileri bilgilendiren bir setTemperature(double temp) metoduna sahip olmalıdır
    • Her gözlemci üzerinde mevcut sıcaklık ile update() metodunu çağıran özel (private) bir notify() metoduna sahip olmalıdır
  • main.cpp: Observer desenini iş başında gösterin.

    Üç girdi okuyun:

    1. İlk ekran için isim (string)
    2. İkinci ekran için isim (string)
    3. Bir sıcaklık değeri (double)

    Bir WeatherStation ve sağlanan isimlerle iki TemperatureDisplay nesnesi oluşturun. Her iki ekranı da istasyona bağlayın (attach), ardından sıcaklığı girdi değerine ayarlayın. Her iki ekran da güncellemeyi otomatik olarak almalı ve mesajlarını yazdırmalıdır.

    Bundan sonra, ilk ekranı ayırın (detach) ve girdiden 5 derece daha yüksek yeni bir sıcaklık ayarlayın. Bu güncellemeyi yalnızca ikinci ekran almalıdır.

Örneğin, Kitchen, Bedroom ve 22.5 girdileriyle:

Kitchen: Temperature is 22.5 degrees
Bedroom: Temperature is 22.5 degrees
Bedroom: Temperature is 27.5 degrees

Office, Lobby ve 18.0 girdileriyle:

Office: Temperature is 18 degrees
Lobby: Temperature is 18 degrees
Lobby: Temperature is 23 degrees

Observer deseninin nasıl gevşek bağlı (loosely coupled) bir sistem oluşturduğuna dikkat edin; hava durumu istasyonunun belirli ekranlar hakkında bir şey bilmesine gerek yoktur, sadece dinleyen herkesi bilgilendirir. Bir gözlemciyi ayırdığınızda, güncellemeleri almayı otomatik olarak durdurur.

Kopya kağıdı

Observer deseni, bir konunun (subject) durumu değiştiğinde tüm gözlemcilerini (observers) otomatik olarak bilgilendirdiği bire-çok bir bağımlılık tanımlar.

Desen iki temel role sahiptir:

  • Subject (Konu): Gözlemcilerin bir listesini tutar ve durum değişikliklerini onlara bildirir
  • Observer (Gözlemci): Bildirimleri almak için bir güncelleme arayüzü uygular

Temel uygulama:

#include <iostream>
#include <vector>
#include <algorithm>

class Observer {
public:
    virtual void update(int value) = 0;
    virtual ~Observer() = default;
};

class Subject {
    std::vector<Observer*> observers;
    int state = 0;
    
public:
    void attach(Observer* obs) {
        observers.push_back(obs);
    }
    
    void detach(Observer* obs) {
        observers.erase(
            std::remove(observers.begin(), observers.end(), obs),
            observers.end());
    }
    
    void setState(int value) {
        state = value;
        notify();
    }
    
    void notify() {
        for (Observer* obs : observers) {
            obs->update(state);
        }
    }
};

class Display : public Observer {
    std::string name;
public:
    Display(const std::string& n) : name(n) {}
    void update(int value) override {
        std::cout << name << " received: " << value << "\n";
    }
};

Temel metotlar:

  • attach(): Bildirimleri almak için bir gözlemci kaydeder
  • detach(): Bir gözlemciyi bildirim listesinden çıkarır
  • notify(): Tüm gözlemciler üzerinde döner ve onların update() metodunu çağırır

Bir nesnedeki değişikliklerin, aralarında sıkı bir bağ (tight coupling) olmadan diğerlerini güncellemeyi gerektirdiği durumlarda Observer desenini kullanın.

Kendin dene

#include <iostream>
#include <string>
#include "WeatherStation.h"

using namespace std;

int main() {
    // Girdileri oku
    string display1Name, display2Name;
    double temperature;
    
    cin >> display1Name;
    cin >> display2Name;
    cin >> temperature;
    
    // TODO: Bir WeatherStation nesnesi oluşturun
    
    // TODO: Giriş adlarıyla iki TemperatureDisplay nesnesi oluşturun
    
    // TODO: Her iki ekranı da hava durumu istasyonuna bağlayın
    
    // TODO: Sıcaklığı giriş değerine ayarlayın
    // (Her iki ekran da mesajlarını yazdırmalıdır)
    
    // TODO: İlk ekranın bağlantısını kesin
    
    // TODO: Sıcaklığı girişten 5 derece daha yükseğe ayarlayın
    // (Sadece ikinci ekran yazdırmalıdır)
    
    return 0;
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler