Observer Design Pattern

Şu aralar daha önceden üzerinden geçtiğim tasarım desenleri ile uğraşıyorum tekrar. Ama bu sefer biraz daha pratik şekilde ilerlemeye çalışıyorum. İlerdikçe de burada hem bana ilerde hatırlamam için not olması hem de ihtiyacı olanların faydalanması için paylaşmaya çalışıyorum.

Son yazımda Strateji tasarım deseninden bahsetmiştim. Bu kez ise Observer tasarım deseninden bahsetmeye çalışacağım. Örneğin bir alışveriş sitesinin kampanyalarından haberdar olmak için maillist’ine kayıt olduğunuzu düşünün, daha sonra bir başkasının da aynı listeye abone olduğunu düşünelim. Bir kampanya olduğunda siteden abone olan herkese bu kampanya gönderilir.  Daha sonradan artık kampanya bilgilerini almak istemezseniz listeden çıkarsınız ve artık yeni kampanya bilgileri diğer abonelere gönderilir.

Observer tasarım deseni de uygulamalarımızdaki bu tarz işlemlerimizi yapmamızı kolaylaştıran bir desendir. Örneğin bir nesnenin durumu değiştiğinde uyarılacak nesneler listesine eklenmiş nesnelerimiz otomatik olarak uyarılır.

Bu desen ile ilgili örneğimi bir önceki strateji deseni örneğim üzerinden yapacağım. Böyle olması biraz daha karışık olmasına sebep oldu ama ezbere kaçmayı önlememi sağladı. Ayrıca iki deseni bir örnek de birleştirmiş oldum. Öncelikle eklememiz gereken yeni arayüz ve sınıfları vereceğim, daha sonra değişiklik yapmamız gereken kısımlardan bahsedeceğim.

İlk olarak biri yayıncı(subject) biri de dinleyici (subscriber,observer) olmak üzere iki interface tanımlayacağım. Daha sonra kullanacağım bütün dinleyici ve yayıncı sınıfları bu sınıflardan türeteceğim.

public interface IYayinci
{
void dinleyiciKaydet(IDinleyici dinleyici);
void dinleyiciCikar(IDinleyici dinleyici);
void dinleyicileriUyar();
}
public interface IDinleyici
{
void guncelle(ArrayList args);
}

Burada IYayinci arayüzümüzde üç adet metodumuz var bunlar uyarılacak nesneleri eklememizi, çıkarmamızı ve nesnenin durumu değiştiğinde listemizdeki nesnelerin uyarılmasını sağlıyor. IDinleyici arayüzündeki metodumuz ise durum değişikliği olduğunda yapılması gereken işlemleri içeren metoddur.

İkinci olarak yayıncı sınıfımızı oluşturuyoruz. Bu sınıfımızda arayüzden aldığı metodları implemente ediyoruz. Ayrıca ben bir adet renkDegisti metodu ekledim ki bu metodu da renk değişimi olduğunda kullanacağız.

public class RenkYayinci : IYayinci
{
ArrayList _dinleyiciler;
ArrayList _args;
public RenkYayinci()
{
_dinleyiciler = new ArrayList();
_args = new ArrayList();
}
public void dinleyiciKaydet(IDinleyici dinleyici)
{
_dinleyiciler.Add(dinleyici);
}
public void dinleyiciCikar(IDinleyici dinleyici)
{
int i = _dinleyiciler.IndexOf(dinleyici);
if (i >= 0)
{
_dinleyiciler.RemoveAt(i);
}
}
public void dinleyicileriUyar()
{
for (int i = 0; i < _dinleyiciler.Count; i++)
{
IDinleyici dinleyici = (IDinleyici)_dinleyiciler[i];
dinleyici.guncelle(_args);
}
}
public void renkDegisti(string renk)
{
_args.Clear();
_args.Add(renk);
dinleyicileriUyar();
}
}

Burada renkDegisti metoduna renk değişkenini almama rağmen bunu arraylist’e atma sebebim IDinleyici arayüzünün sadece renk için özelleşmesini engellemek ve daha sonra da kullanmak istememdir. Daha sonra dinleyicileriUyar() metodunu çağırıyoruz ve bütün ekli nesneleri haberdar ediyoruz.

Artık eski sınıflarımızda değişiklik yapmaya başlayabiliriz. Öncelikle Daire ve Kare Sınıflarımızı aşağıdaki şekle getiriyoruz.

public class Kare : Sekil, IDinleyici
{
private RenkYayinci _renkYayinci;
public Kare(Dictionary<string, int> degerler, RenkYayinci renkYayinci)
{
_cevre = new KareCevre();
_degerler = degerler;
this._renkYayinci = renkYayinci;
this._renkYayinci.dinleyiciKaydet(this);
}
public void guncelle(ArrayList args)
{
Console.WriteLine(“\nKare kenar renkler değişti ” + args[0].ToString());
}
}

 

public class Daire : Sekil, IDinleyici
{
private RenkYayinci _renkYayinci;
public Daire(Dictionary<string, int> degerler, RenkYayinci renkYayinci)
{
_cevre = new DaireCevre();
_degerler = degerler;
this._renkYayinci = renkYayinci;
this._renkYayinci.dinleyiciKaydet(this);
}
public void guncelle(ArrayList args)
{
Console.WriteLine(“\nDaire çember içi renkler değişti” + args[0].ToString());
}
}

Sınıf tanımlamalarımızda koyu ile işaretli yerleri değiştiriyoruz. Burada öncelikle constructor metodumuzda parametre olarak aldığımız yayıncıya nesnemizi ekliyoruz. Daha sonra dinleyici arayüzünden alınan guncelle metodunu implemente ediyoruz.

Artık desenimizi deneyebiliriz. Önceki yazımızda bulunan örnekteki main metodunu aşağıdaki şekilde değiştiriyoruz.

static void Main(string[] args)
{
Dictionary<string, int> dd = new Dictionary<string, int>();
dd.Add(“BirKenar”, 4);
RenkYayinci renkYayinci = new RenkYayinci();
Sekil sk = new Kare(dd, renkYayinci);
renkYayinci.renkDegisti(“mavi”);
Console.WriteLine(sk.cevreHesapla(dd).ToString());
Console.ReadLine();
}

Programımızı derleyip çalıştırdığımızda karşımızda

Kare kenar renkler değişti mavi

16

çıktısını görebiliriz.