Observe Pattern Nedir ? Nasıl Gerçeklenir?

Özgür Karadeniz
Nettsi Bilişim Teknoloji A.Ş.
4 min readJul 6, 2020

Merhaba, bugünkü konumuz Observe Pattern nedir ve C++ ile nasıl gerçeklenir bunu anlatmaya çalışacağım.

Observe Pattern Nedir ve Nerelerde Kullanılır?

Bir nesnenin durumunun değişmesi ile o nesneye bağlı ya da ilgili diğer nesnelerin bu durumdan haberdar olmasını istiyorsak kullanabiliriz. Bunu örnek bir senaryo üzerinden anlatayım. İki tür nesnemiz olduğunu düşünelim. Mağaza ve Müşteri. Bir grup müşteriniz mağanıza gelecek yeni model telefon için bekliyorlar. Ürün stoklarınıza girdiği zaman bundan haberdar olmak istiyorlar.

Müşteri belirli aralıklar ile mağazaya gelebilir, ürünün stoklarda olup olmadığını kontrol edebilir. Bu günümüz dünyasında kabul edilebilir bir yöntem değil.

Bir başka yol ise ürün stoklarınıza girdiği anda müşterilerinizle mail yolu ile iletişime geçmek. Bu tonla mail kullanılacağı için spam kullanıma girecek. Bu ürün ile ilgilenmeyen müşterileriniz karşısında sizin itibarınızı düşürebilir. Bu durumu observer pattern ile çözebiliriz.

Observe patern bir subscriber mekanizması önerir. Bu subscriber’ları tek tek nesnelerin o yayıncıdan gelen bilgileri alabilmesi için bir abonelik mekanizması gibi düşünebiliriz. Herhangi bir durumdan ya da olaydan haberdar olmak isteyenler bir arayüz yardımı ile “register” ya da “subscriber” olurlar .

İstenilen olay olduğunda aboneleri kontrol eder ve ilgili bildirim fonksiyonunu çağırarak subscriber’ları bilgilendirir.

Şimdi ise gerçekleme üzerine çalışalım. Senaryomuz şöyle olsun; Sizden veri alan bir çok farklı müşteriniz var. Bu müşterilerinize hava durumu değiştirdikçe bilgi veriyorsunuz. Öncelikle neyi update edeceğimize ilişkin bir observer’a ihtiyacımız var.

Observer.hpp

#ifndef OBSERVER_PATTERN_OBSERVER_HPP#define OBSERVER_PATTERN_OBSERVER_HPPclass Observer {public:/*** Update the state of this observer* @param temp new temperaure* @param humidity new humidity* @param pressure new pressure*/virtual void update(float temp, float humidity, float pressure) = 0;};#endif //OBSERVER_PATTERN_OBSERVER_HPP

Şimdi ise bir subject interface’ine ihtiyacımız var. Register olmak isteyen modüllerin gerçeklemesi gereken fonksiyonları burada tanımlıyoruz. Bunları pure virtual olarak tanımlamak zorundayım.

Subject.hpp

#ifndef OBSERVER_PATTERN_SUBJECT_HPP#define OBSERVER_PATTERN_SUBJECT_HPP#include "Observer.hpp"class Subject {public:/*** Register an observer* @param observer the observer object to be registered*/virtual void addSubscriber(Observer *observer) = 0;/*** Unregister an observer* @param observer the observer object to be unregistered*/virtual void removeSubscriber(Observer *observer) = 0;/*** Notify all the registered observers when a change happens*/virtual void notifyObservers() = 0;};#endif //OBSERVER_PATTERN_SUBJECT_HPP

Şimdi ise subject üzerinden türeyecek sınıflara ihtiyacımız var. Ben bunları WeatherData.hpp ve WeatherData.cpp olarak tanımlayacağım. Kod şekilde göstermek gerekirse;

WeatherData.hpp

#ifndef OBSERVER_PATTERN_WEATHERDATA_HPP#define OBSERVER_PATTERN_WEATHERDATA_HPP#include <vector>#include <algorithm>#include <iostream>#include "Subject.hpp"#include "Observer.hpp"class WeatherData : public Subject {public:void addSubscriber(Observer *observer) override;void removeSubscriber(Observer *observer) override;void notifyObservers() override;/*** Set the new state of the weather station* @param temp new temperature* @param humidity new humidity* @param pressure new pressure*/void setState(float temp, float humidity, float pressure);};#endif //OBSERVER_PATTERN_WEATHERDATA_HPP

WeatherData.cpp

#include "WeatherData.hpp"void WeatherData::addSubscriber(Observer *observer) {observers.push_back(observer);}void WeatherData::removeSubscriber(Observer *observer) {// find the observerauto iterator = std::find(observers.begin(), observers.end(), observer);if (iterator != observers.end()) { // observer foundobservers.erase(iterator); // remove the observer}}void WeatherData::notifyObservers() {for (Observer *observer : observers) { // notify all observersobserver->update(temp, humidity, pressure);}}void WeatherData::setState(float temp, float humidity, float pressure) {this->temp = temp;this->humidity = humidity;this->pressure = pressure;std::cout << std::endl;notifyObservers();}

Yukarıdaki kod bloğundan göreceğiniz şekilde notifyObservers çağrıldığı zaman sisteme register olan tüm subscriberlar bilgilendiriliyor. Burada özelleştirmeler yapmak mümkün. Özel bir subscriber’a yayın yapmak sizin elinizde. Şimdi ise bize register olacak client.cpp ve client.hpp ‘nin kodlarına bakalım.

Client.hpp

#ifndef OBSERVER_PATTERN_CLIENT_1_HPP#define OBSERVER_PATTERN_CLIENT_1_HPP#include <iostream>#include "Observer.hpp"class Client : public Observer {int id;public:Client(int id);virtual void update(float temp, float humidity, float pressure) override;
};
#endif //OBSERVER_PATTERN_CLIENT_1_HPP

Client.cpp

#include "Client.hpp"void Client::update(float temp, float humidity, float pressure) {// print the changed valuesstd::cout << "---Client (" << id << ") Data---\tTemperature: " << temp<< "\tHumidity: " << humidity<< "\tPressure: " << pressure<< std::endl;}Client::Client(int id) {
this->id = id;
}

Şimdi test aşamasına geçelim. Öncelikle kaç tane client istiyorsak o kadar client yaratmamız gerekecek ve sonra bunları Weather data üzerinden subscriber ekleyerek observer pattern’a uygun hale getireceğiz.

main.cpp

#include <iostream>#include "WeatherData.hpp"#include "Client.hpp"int main() {WeatherData weatherStation;Client one(1), two(2), three(3);float temp, humidity, pressure;weatherStation.addSubscriber(&one);weatherStation.addSubscriber(&two);weatherStation.addSubscriber(&three);std::cout << "Enter Temperature, Humidity, Pressure (seperated by spaces) << ";std::cin >> temp >> humidity >> pressure;weatherStation.setState(temp,humidity,pressure);weatherStation.removeSubscriber(&two);std::cout << "\n\nEnter Temperature, Humidity, Pressure (seperated by spaces) << ";std::cin >> temp >> humidity >> pressure;weatherStation.setState(temp,humidity,pressure);return 0;}

Çıktılar işe su şekilde olacak.

Öncelikle tüm clientlar’a haber veriyor daha sonra bir subscriber remove ediliyor. Ondan sonra sadece 1 ve 3 numaraları subscriber’a yayın yapıyor. Basit bir şekilde böyle örnekleyebiliriz.

Aslında observer pattern tarzında geliştirmeler için kullanacağınız güzel backend kütüphaneleri var. Özellike ben boost.signalsv2 ve apache kafka tavsiye ederim.

Referanslar:

https://medium.com/@gayashanbc/explore-the-observer-design-pattern-with-c-8592459b0486
https://refactoring.guru/design-patterns/observer

--

--