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

Overcoming Event Size Limits with the Conditional Claim-Check Pattern in Event-Driven Architectures

{:en}In today’s technological age, we typically build our application solutions on event-driven architecture in order…

2 months ago

Securing the Supply Chain of Containerized Applications to Reduce Security Risks (Policy Enforcement-Automated Governance with OPA Gatekeeper and Ratify) – Part 2

{:tr} Makalenin ilk bölümünde, Software Supply Chain güvenliğinin öneminden ve containerized uygulamaların güvenlik risklerini azaltabilmek…

7 months ago

Securing the Supply Chain of Containerized Applications to Reduce Security Risks (Security Scanning, SBOMs, Signing&Verifying Artifacts) – Part 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.…

9 months ago

Delegating Identity & Access Management to Azure AD B2C and Integrating with .NET

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

1 year ago

How to Order Events in Microservices by Using Azure Service Bus (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 years ago

Providing Atomicity for Eventual Consistency with Outbox Pattern in .NET Microservices

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

2 years ago