Mediator Design Pattern

Mediator Design Pattern

Mediator design patternini birbirleriyle ilişkili eş görevli bir grup nesneyi tek merkezden yönetmek ve aralarında gevşek bağlı(loosely coupled) sistemler kurmak istediğimiz durumlarda kullanabiliriz. Tanımı netleştirebilmek adına bir örnek üzerinden devam edelim.

Birbiriyle konuşması gereken bir grup nesnemiz olduğunu varsayalım. Genelde bu varsayım için iki klasik örnek vardır. Biri chatbot örneği diğeri ise hava yolu örneği.

Chatbot örneği üzerinden gidersek, birbiriyle konuşması gereken bir grup nesnemiz chatleşecek olan kişileri temsil eden nesneler, mediator classımızda bu kişilerin bir arada bulunup birbirleriyle ilişki kurduğu chatroomdur. Normal şartlarda chatgrupları, chatleşecek kişiler vs için ayrı nesneler yarattığımzda bu kişileri birbiriyle konuşturabilmek için birbirine referans vermemiz gerekir. Ancak bu classların birbirine sıkı sıkıya bağlı olması (Tightly coupling) demektir ve istemediğimiz bir durumdur. Sistemlerimizi olabildiğince gevşek bağlı inşa etmeliyiz. Chat örneği için bütün kullanıcıların birbirleriyle olan ilişkisini ve mesajlaşmasını, kullanıcıları birbirine dokundurmadan bir ara katman yani mediator class üzerinden yönetiriz.

Ya da bir diğer örnek olan havayolu örneği, gün içerisinde havaalanına iniş kalkış yapan onlarca hatta yüzlerce uçak vardır ve bunların birbirleriyle senkron hareket etmesi yani birbirlerinden haberdar olması gerekir. Ancak bu birbirlerinden haberdar olma durumu için bütün uçakların direkt olarak birbirleriyle iletişim kurdukları senaryoyu bir düşünün. Tamamen bir kaos ve spagetti durum. Bunun yerine bir kule uçaklar arasındaki iletişimi ve organizasyonu sağlar ki bu kule tam olarak mediator classtır.

Sonuç olarak Mediator design patterninin bize söylediği şey, bu birbiriyle ilişki içinde olması gereken nesneleri ki bunlar birbirleriyle chatleşecek userlar olabilir, birbirleriyle iniş kalkış için iletişim kurması gereken uçak nesneleri olabilir, tek bir merkez içerisinde (mediator classta) birbiriyle konuşturun. Böylece nesneler arasında gevşek bağlı sistemler kurmuş olursunuz ve karmaşıklığı minimuma indirirsiniz.

Mediator patterni kullanabileceğimiz caseleri madde madde sıralarsak ;

  • Birbirine gönderme yapan,interaction içinde olan birden fazla objectiniz varsa
  • Bu ilişkileri farklı bir katmanda yönetmek istiyorsak

Bu sayede nesneler birbirine referans vermez ve uzun vadede genişletilebilir bakımı kolay bir kod oluşmuş olur. Ancak mediator design patterninin faydaları olduğu gibi endişe veren noktaları da vardır. Mesela, bu gibi kritik işleri tek bir mediator class üzerinden yönetmek bize single point of failure yani tek nokta sıkıntısı yaşatabilir. Yani mediator classındaki herhangi bir sıkıntı tüm sistemi çökertir.

  • Katılımcı classı collegues yani senaryodaki userların parent classıdır. Mesaj gonderme ve mesaj alma özellikleri parent class üzerinden yönetilir. Mesaj gönderilirken yukarıda da bahsettiğim gibi, direkt diğer usera gönderilmek yerine mediator üzerinden gönderilir.
public class Katilimci
{
     public string Ad { get; }
     public ConcreteMediator concreteMediator { set; get; }

    public Katilimci(string ad)
    {
           this.Ad = ad;
    }

    public void MesajGonder(string kime, string mesaj)
    {
        concreteMediator.MesajGonder(Ad, kime, mesaj);
    }


    public virtual void MesajAlici(string kimden, string mesaj)
    {
         Console.WriteLine("{0} to {1}: '{2}'", kimden, Ad, mesaj);
    }

}
  • ConcreteColleague1  birinci concrete colleguage classıdır. Yani bir gruba ait chat userı temsil eder. Mesaj alma özelliğine sahiptir ki bunu da parent classı olan Katilimci classının MesajAlici metodu üzerinden yapar.
class ConcreteColleague1 : Katilimci
{

    public ConcreteColleague1(string ad) : base(ad)
    {

    }

    public override void MesajAlici(string kimden, string mesaj)
    {
          Console.Write("Kime -> ConcreteColleague1: ");
          base.MesajAlici(kimden, mesaj);
    }

}
  • ConcreteColleague2 ikinci concrete colleguage classıdır.Yani diğer bir gruba ait chat userı temsil eder. Mesaj alma özelliğine sahiptir ki bunu da parent classı olan Katilimci classının MesajAlici metodu üzerinden yapar.
class ConcreteColleague2 : Katilimci
{

     public ConcreteColleague2(string ad) : base(ad)
     {

     }      

     public override void MesajAlici(string kimden, string mesaj)
     {
           Console.Write("Kime -> ConcreteColleague2: "); 
           base.MesajAlici(kimden, mesaj);
     } 

}

public abstract class Mediator
{
      public abstract void KayitOl(Katilimci katilimci);

      public abstract void MesajGonder(string kimden, string kime, string mesaj);
}
  • Mediator classımız, içerisinde birbiriyle haberleşecek tüm nesneleri Dictionary olarak tutar. Yani senaryo odaklı düşünürsek, siz bir chat usersınız ve bir chatroom’a register oldunuz, chat room sizi de dahil ederek chatroomda kaç kişi varsa bunu bilir. Bunu da kodda KayitOl() metodu üzerinden yapıyoruz. Bunun dışında bir de MesajGonder() metodumuz mevcut. Bu metot üzerinden userlar birbirlerine mesaj gönderirler. Yani yukarıda bahsettiğim gibi, userlar birbirleriyle haberleşecekse bunu mediatorun Mesaj gonder metodu üzerinden yaparlar. Birbirlerine direkt olarak bağlı değillerdir.
    Mediatorun mesaj gönder metodu da mesaji alır ve uygun alıcıya iletir.
public class ConcreteMediator : Mediator
{

    private Dictionary<string, Katilimci> _katilimcilar = new Dictionary<string, Katilimci>();


    public override void KayitOl(Katilimci katilimci)
    {
         if (!_katilimcilar.ContainsValue(katilimci))
         {
               _katilimcilar[katilimci.Ad] = katilimci;
         }

            katilimci.concreteMediator = this;
    }

    public override void MesajGonder(string kimden, string kime, string mesaj)
    {

         Katilimci katilimci = _katilimcilar[kime];

           if (katilimci != null)
           {
              katilimci.MesajAlici(kimden, mesaj);
           }

     }

 }
 static void Main(string[] args)
 {

   ConcreteMediator sohbetOdasi = new ConcreteMediator();

   Katilimci Can = new ConcreteColleague1("Can"); 
   Katilimci Canan = new ConcreteColleague1("Canan");
  -Katilimci Baris = new ConcreteColleague2("Barış");
   Katilimci Ahmet = new ConcreteColleague2("Ahmet"); 
   Katilimci Selvi = new ConcreteColleague1("Selvi");


   sohbetOdasi.KayitOl(Can); 
   sohbetOdasi.KayitOl(Canan); 
   sohbetOdasi.KayitOl(Baris); 
   sohbetOdasi.KayitOl(Ahmet); 
   sohbetOdasi.KayitOl(Selvi);


   Canan.MesajGonder("Can", "Selam Can Yemeğe Çıkacakmısın ?"); 
   Baris.MesajGonder("Ahmet", "İstediğim evraklar hazır mı ?"); 
   Canan.MesajGonder("Ahmet", "Toplantı saat 3'te ");
   Ahmet.MesajGonder("Barış", "İstediğin evraklar hazır");

 }