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ü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.
Gerçekten şu ana kadar gördüğüm en açıklayıcı örnek.Teşekkürler
Teşekkürler.