10 Ağustos 2017 Perşembe

GoF - Observer Örüntüsü

Delegate ve Event
delegate ve event, Observer ve Observable örüntüsüne uygun olarak kullanılabilir.

Delegate C'deki function pointer, C++'taki std::function veya Java'daki tek metodu olan bir interface olarak düşünülebilir. Event ise Function Pointer listesi olarak düşünülebilir. Bu ikili aşağıdaki gibi tanımlanıyorlar.

Delegate tanımı
public delegate void MyventHandler(object sender, EventArgs e);
Delegate tanımında ilk parametrenin sender olması, Microsoft tarafından tavsiye edilen şey. Ne faydası var ben de tam anlamadım.

Event Tanımlama
Şöyle yaparız
public event MyEventHandler SomethingHappened;
Event kayıtlı tüm delegate'leri aynı parametre ile çağırır. Açıklaması şöyle
Events are an extremely convenient way for an object to collate 'handler' delegate methods, and then to be able to call them all with a set of parameters.
Event Listesine Ekleme Yapma
C# 2.0'dan önce aşağıdaki gibi delegate metodu new'lenerek yapılıyordu.
watcher.Created += new FileSystemEventHandler(OnChanged);
Ancak yeni kodlarda buna gerek yok.
watcher.Created += OnChanged;
Boş Event Nesnesi
Delegate eklenmemiş event nesnesi null nesne gibi çalışır. Dolayısıyla her zaman null kontrolü yapmak gerekir.
if (MyEvent != null)
    MyEvent(this, e);
Bazıları böyle çalışmayı sevmiyor. Bu kontrolü yapmamak için event'i ilklendirirken boş bir delegate ekliyorlar. Bu kodun çok az bir performans etkisi dışında bir kötü bir tarafı yok.
public event EventType MyEvent = delegate {};
Event ve Thread Safe Çalışma
Event'i çağırırken kopyasını alıp çağırmak thread safe olması için yeterli.
var handler = Complete;
if(handler != null)
{
  handler();
}
Hazır Delegate Sınıfları
C#'ta hazır gelen Action Delegate, Function Delegate sınıfları var.

Kendi Event Hiyerarşim
Şöyle bir hiyerarşi kurduğumuzu olsun
public class Event {}
public class EventA : Event {}
public class EventB : Event {}
Bu hiyerarşi için bir delegate tanımlayalım
delegate void HandlerDelegate<TEvent>(TEvent ev) where TEvent : Event;
Daha sonra delegate'ı bir sınıf ile sarmayalım.
class EventManager
{
  Dictionary<Type, Delegate> delegateMap = new Dictionary<Type, Delegate>();

  void Dispatch<TEvent>(TEvent ev) where TEvent : Event
  {
    Delegate d;
    if (delegateMap.TryGetValue(typeof(TEvent), out d))
    {
      var handler = (HandlerDelegate<TEvent>)d;
      handler(ev);
    }
  }

  void Register<TEvent>(HandlerDelegate<TEvent> handler) where TEvent : Event
  {
    delegateMap.Add(typeof(TEvent), handler);
  }
}
Bir de Observer yazalım.
public class EventListener
{
  public EventListener(EventManager evtMgr)
  {
    evtMgr.Register<EventA>(this.HandleEventA);
    evtMgr.Register<EventB>(this.HandleEventB);
  }

  public void HandleEventA(EventA ev)
  {
    //... do stuff
  }

  public void HandleEventB(EventB ev)
  {
    //... do stuff
  }
}

Hiç yorum yok:

Yorum Gönder