Tasarım desenleri ile ilgili daha önceki makalemde Behavioral tasarım kalıpları gurubunda yer alan Memento tasarım deseni ile giriş yapmıştık. Bu makalemde de yine Behavioral tasarım kalıpları gurubunda yer alan Observer tasarım deseni ile devam edeceğim.

Observer tasarım desenindeki amaç:

Tasarlanmış olan sistem içerisinde, değişimini izlemek istediğimiz bir değer için kullanılır.

UML Diagramına bir göz atalım:

 

Subject: Takip edilecek olan nesnemiz.
Observer: Abstract gözlemci sınıfımız. Soyutlamanın sebebi ise birden fazla gözlemci tarafından takip edilebilmesini sağlamak.
ConcreteObserver: Gerçek takip eden nesnemiz.

Basit bir örnek yaparak konuyu daha iyi pekiştirelim.

Örneğimizi bir e-ticaret sitesindeki kullanıcı üzerine düşünebiliriz. İstediğimiz bir ürünün stoğundaki bir değişim veya fiyatındaki bir değişimi gözlemlemek/takip etmek isteyebiliriz.

İlk başta Subject görevini üstlenecek olan yani takip edilecek nesnemiz olan Product sınıfımızı oluşturalım.

    /// <summary>
    /// Subject - Takip edilecek olan nesnemiz.
    /// </summary>
    class Product
    {
        // Gözlemleyicilerimizi tutacağımız listemiz.
        private List<Observer> _observers = new List<Observer>();

        public void Attach(Observer observer)
        {
            _observers.Add(observer);
        }

        public void Detach(Observer observer)
        {
            _observers.Remove(observer);
        }

        private void Notify()
        {
            // Herhangi bir değişiklik olduğunda gözlemleyicilerimizin Update metotunu tetikleterek istenilen aksiyonu gerçekleştirebiliriz. Örneğin: Kullanıcılara e-posta atmak gibi düşünebilirsiniz.
            _observers.ForEach(o => { o.Update(); });
        }

        public void ChangeStock()
        {
            ... stok değiştirilme işlemleri
            // Stok değiştirildiğinde gözlemcilerimize bildiriyoruz.
            this.Notify();
        }
    }

Şimdi Observer olan soyut sınıfımızı hazırlayalım ve ardından gerçek uygulayan sınıfımız olan (ConcreteObserver) CustomerObserver‘ı oluşturalım.

    /// <summary>
    /// Observer - Soyut sınıfımız.
    /// Soyutlamamızın nedeni ise birden fazla sınıf tarafındanda takip edilmesini sağlamak.
    /// </summary>
    abstract class Observer
    {
        // Herhangi bir değişimde gözlemleyiciler tarafından yapılması istenilen aksiyonlar.
        public abstract void Update();
    }

Observer soyut sınıfınıda hazırladık ve içerisinde değişimler karşılığında yaptırılmak istenilen aksiyonu yani Update metotunu tanımladık.

Şimdi CustomerObserver sınıfına bir göz atalım.

    /// <summary>
    /// ConcreteObserver - Gerçek takip eden nesnemiz.
    /// </summary>
    class CustomerObserver : Observer
    {
        public override void Update()
        {
            Console.WriteLine("Takip ettiğim ürünün stoğu değişti.");
            Console.ReadLine();
        }
    }

Değişim sonrasında ise gözlemleyecek olan sınıfımız CustomerObserver update işlemi sonrasında gerçekleştireceği olan Update aksiyonunu uyguladık. Siz burada business rule’larınıza göre istediğinizi yapabilirsiniz. Örneğin kullanıcı e-posta ile bilgilendirilmek istenebilir gibi.

Şimdi kullanımına bir göz atalım:

        static void Main(string[] args)
        {
            Product product = new Product();

            // İlgili gözlemleyicimizi product nesnemize ekliyoruz ki değişim sonrasında notify edebilelim.
            product.Attach(new CustomerObserver());

            // Ürün stoğunu değiştiriyoruz.
            product.ChangeStock();
        }

İşte bu kadar, Product nesnemize yani subject’imize eklenen her gözlemleyici, ürünün stoğu değişmesi sonrasında notify ile bilgilendirilecek. Biz örneğimiz gereği aksiyon olarak ekrana “Takip ettiğim ürünün stoğu değişti.” yazdırdık.

Uygulamayı çalıştırdığınızda böyle bir ekran göreceksiniz.

Observer tasarım desenini kısaca özetlediğimizde yayımcılar(Publishers) ve aboneler(Subscribers) modelinin uygulandığını düşünebiliriz. Bire-çok ilişkisi ile bağlı nesnelere, olayları iletmek olduğunu da diyebiliriz

Kullanım alanı olarak çok sık karşımıza çıkmaktadır aslında. MVC mimarisine baktığınızda:

 

Model üzerindeki bir değişikliği View’a notify ediliyor. Model burada view’a independent bir durumda.

Bununla ilgili msdn üzerinde güzel bir yazıyı sizinle paylaşmak istiyorum:

When a model changes, the model iterates through all registered observers and notifies them of the change. This approach is often called “publish-subscribe.” The model never requires specific information about any views.

Başka bir kullanım örneği daha vermek gerekirse de event-based programlamada event-delegate ilişkileri örnek gösterilebilir.

Umarım yeterli bilgi ve anlaşılabilir bir örnek olmuştur. Bir sonraki makalemde görüşmek dileğiyle.

 

Gökhan Gökalp

View Comments

  • Güzel açıklama olmuş. Belki Observer soyut sınıfı yerine arayüz tanımlamak daha uygun olabilir. Java'da benzer bir tasarım vardı, bu sebeple asıl (alt) observer sınıflar sadece ondan türemek zorunda kalıyordu.

    • Teşekkür ederim, interface veya abstract olarak tanımlanabilir. Tabi bu domainimize görede spesifikleşebilir. Örneğin: Observer'larımızın arasında şablon bir fonksiyonu gerçekleştirmek istiyorsak, abstract sınıfımızın içinde Template Method tasarımıda uygulanabilir ve kod tekrarının önünede geçebiliriz fakat interface'de sadece method imzaları bulunabileceği için bu mümkün değildir tabi bu domaine göre spesifikleşebilir.

Recent Posts

Containerized Uygulamaların Supply Chain’ini Güvence Altına Alarak Güvenlik Risklerini Azaltma (Güvenlik Taraması, SBOM’lar, Artifact’lerin İmzalanması ve Doğrulanması) – Bölüm 1

{:tr}Bildiğimiz gibi modern yazılım geliştirme ortamında containerization'ın benimsenmesi, uygulamaların oluşturulma ve dağıtılma şekillerini oldukça değiştirdi.…

8 ay ago

Identity & Access Management İşlemlerini Azure AD B2C ile .NET Ortamında Gerçekleştirmek

{:tr}Bildiğimiz gibi bir ürün geliştirirken olabildiğince farklı cloud çözümlerinden faydalanmak, harcanacak zaman ve karmaşıklığın yanı…

12 ay ago

Azure Service Bus Kullanarak Microservice’lerde Event’ler Nasıl Sıralanır (FIFO Consumers)

{:tr}Bazen bazı senaryolar vardır karmaşıklığını veya eksi yanlarını bildiğimiz halde implemente etmekten kaçamadığımız veya implemente…

2 yıl ago

.NET Microservice’lerinde Outbox Pattern’ı ile Eventual Consistency için Atomicity Sağlama

{:tr}Bildiğimiz gibi microservice architecture'ına adapte olmanın bir çok artı noktası olduğu gibi, maalesef getirdiği bazı…

2 yıl ago

Dapr ve .NET Kullanarak Minimum Efor ile Microservice’ler Geliştirmek – 02 (Azure Container Apps)

{:tr}Bir önceki makale serisinde Dapr projesinden ve faydalarından bahsedip, local ortamda self-hosted mode olarak .NET…

2 yıl ago