Yazılım Mimarileri ve Tasarım Desenleri Üzerine

C# Mediator Design Pattern(Mediator Tasarım Deseni)

Merhaba,

Bu makalemizde Davranışsal Tasarım Kalıplarından(Behavioral Patterns) olan Mediator Tasarım Desenini(Mediator Design Pattern) bol pratiksel senaryolar eşliğinde inceliyor olacağız. İçeriğe başlamadan önce şahsi fikrimi beyan ederek bir girizgâh eylemek isterim ki; bana sorarsanız doğası itibariyle design pattern’lar arasında kullanım sahası açısından oldukça kısır olan lakin son yıllarda MediatR gibi paketlerin popülaritesinin artmasıyla oldukça yaygınlaşan bir tasarım desenini ele alıyor olacağız. Dolayısıyla bu desenin, salt haliyle anlaşılabilmesi ve gerçek senaryolara uyarlanabilmesi oldukça zor ve zahmetli olduğu için ben deniz bir kaç farklı senaryoyla konuyu inceleyecek ve kavranılabilirliği arttırmak için ince dokunuşlarla içeriği destekleyeceğim… Tabi bu süreçte okurken sizlerin ise çay veya kahveyle eşlik etmeniz kafi olacaktır 🙂

Hadi başlayalım…

Mediator Tasarım Kalıbının Amacı Nedir?

Nesneler arasındaki kaotik bağımlılıkları azaltmanıza izin veren davranışsal bir tasarım modelidir.

Hoca, nesneler arasındaki kaotik bağımlılıklardan kastın ne la Allahisen?
Tamam, bunu şöyle örneklendirelim. Müşteri profilleri oluşturmak ve düzenlemek için textboxlar, checkboxlar, buttonlar vs. gibi çeşitli form yapılanmalarının ve bunların kendi aralarında hizalı ve işlevsel bir diyaloğunun olduğunu varsayalım.

Uygulama geliştikçe kontroller arasındaki ilişkiler daha da kaotik hale gelmektedir.

İşte bu işleminizi yukarıdaki gibi her bir kontrolün birbiriyle temasını sağlayacak şekilde düzenlerseniz kastedilen kaotik bağımlılıklar söz konusudur diyebiliriz.

Bir sınıfın sahip olduğu bağımlılıklar ne kadar azsa, o sınıfı değiştirmek, genişletmek veya yeniden kullanmak o kadar kolay olacaktır.

Mediator tasarım kalıbı ise bu kaotik gidişatı aşağıdaki gibi olması gereken hale getirir ve nesneler arasındaki bağımlılıkları tek bir merkezden yönetimi sağlayarak azaltmamıza imkan tanır.

Mediator nesnesi aracılığıyla tüm kontroller dolaylı iletişim kurmalıdır.

Böylece nesnelerin birbirleriyle nasıl konuşacaklarını değil, ne konuşacaklarıyla ilgilenen bir tasarım gerçekleştirilmiş olur. İdeal olanda budur!

Mediator, birbirleriyle iletişimde olması gereken nesnelerin iletişimlerinin birebir olmasından ziyade, birbirlerinden bağımsız olacak şekilde olmasını önerir. İki nesne arasında varsa iletişim bunun kesilmesini, yerine bu nesnelerin birbirlerine olacak çağrılarını uygun şekilde yönlendirecek olan özel bir aracı(Mediator) nesnesi üzerinden dolaylı olarak sağlanmasını ister.

Mediator modeli, tek bir aracı(mediator) nesnesi içerisinde çeşitli nesneler arasındaki karmaşık ilişkiler ağını yönetmenize olanak tanır.

Gerçek Dünya Analojisi

Uçak pilotları, bir sonraki uçağa kimin ineceğine karar verirken birbirleriyle doğrudan konuşmazlar. Tüm iletişim kontrol kulesiyle gerçekleştirilir.

Mediator deyince genellikle uçakların birbirleriyle olan haberleşmesi üzerinden örneklendirme yapılır. Eee haliyle bu da durumu özetleyebilmemizi sağlayan güzel bir argümandır. Lakin bu içeriğimizde pratiksel olarak çok farklı örnekler üzerinden mediator senaryoları ele alacağım. Şimdilik gelin, ilk olarak gerçek dünya analojisinde genelin kabul ettiği uçak metaforunu ele alalım…

Havaalanı iniş pistine yaklaşan yahut kalkışa hazırlanan uçaklar, davranışlarını diğer uçakların durumuna göre belirlemek ve uygunsa eğer aksiyon almak mecburiyetindedirler. İşte hal böyleyken uçaklar birbirleriyle iletişim kurmaktansa kule vasıtasıyla iletişimlerini merkezi olarak sağlamaktadırlar. Neden mi? Çünkü her bir uçak bir diğeriyle iletişim kurmaya kalkarsa eğer inanılmaz bir karışıklık ve başta da söylediğimiz gibi kaotik durum söz konusu olacaktır.

Anlayacağınız bu tarz muhabbetlerin sürmemesi için uçaklar arası tüm iletişim kule aracılığıyla gerçekleştirilmekte ve yapılacak aksiyona göre karar mekanizması tek elden yönetilmektedir. Haliyle uçaklar kule vasıtasıyla hava trafik kontrolünü sağlayacaklarından dolayı, diğer uçakların ne yaptığı yahut nasıl aksiyon alacağıyla değil bizzat kendi davranışıyla ilgilenmiş olacaktır.

Şimdi konuyu teoride daha iyi anlayabilmek için bir başka örnek üzerinden analoji gerçekleştirelim. Bir sistemdeki kullanıcıların belli başlı gruplara dahil olduğunu düşünelim ve her kullanıcının bir veya daha fazla grubun üyesi olabileceğini ve aynı şekilde her gruba hiç kullanıcı üye olmayacağı gibi bir veya birden fazla üye olabileceğini varsayalım.
Bu ihtiyacı yandaki gibi çözümlediğimiz durumda arapsaçı tabirinin tam karşılığını görmüş olacağız. Düşünsenize, bu şekilde yapılan bir modellemede herhangi bir grubun üzerinde değişiklik ihtiyacı olduğu zaman tüm kullanıcılar istemsizce bu değişiklikten etkilenecektir! Ne kadar kötü!  
 
 
 

Halbuki bu modellemeyi yandaki gibi merkezi bir sınıf üzerinden gerçekleştirip, kullanıcılar ile gruplar arasındaki ilişkiyi soyutladığımızda oldukça avantajlı bir tasarım karşımıza çıkmaktadır. Böyle bir tasarımda yapılacak tüm değişiklikler kolayca gerçekleştirilebilir.

Bir sistemi birçok nesneye bölmek/parçalamak genellikle yeniden kullanılabilirliği(reusability) arttırır. Ancak bu nesneler arasında artan ilişkisel bağlar, tekrar kullanılabilirlik açısından negatif etki gösterir. Mediator nesnesi, nesneler arasındaki tüm ilişkileri kapsülleyerek, iletişim merkezi görevi görür. Etkileşimleri kontrol ve koordine etmekten sorumludur. Ayrıca nesnelerin açıkça birbirlerine referansta bulunmasını engelleyerek gevşek bağlanmayı teşvik eder.

Mediator Anatomisi


Mediator tasarımı yukarıdaki diyagramda da görüldüğü üzere; ‘Mediator‘, ‘Colleague‘, ‘Concrete Mediator‘ ve ‘Concrete Colleague‘ aktörlerinin bir araya gelmesiyle oluşturulur.

Şimdi gelin bu aktörlerin kim olduklarını sorumluluklarıyla beraber inceleyelim;

Mediator Stratejisinin Uygulanması

Mediator stratejisinin nasıl uygulandığını izah edebilmek için belli başlı senaryolar üzerinden konuyu ele almakta fayda olacağı kanaatindeyim. Bunun için sizlere birbirinden farklı üç senaryo üzerinden anlatım sergilemeye çalışacağım. Şimdi gelin 1. senaryodan konuyu pratikte inceleyelim;

SENARYO 1
Bir bilgisayardaki çeşitli birimler arasındaki etkileşimlerin esas olarak anakart üzerinden yapıldığını hepimiz biliyoruz. Eğer anakart olmasaydı, bu birimlerin etkileşime girebilmesi için birbirleriyle haberleşmesi gerekecekti. Böyle bir durumda ise oldukça karışıklık söz konusu olacağı aşikar. Dolayısıyla her birim sade ve sadece anakartla etkileşime girerek, birimler arasındaki haberleşme sorumluluğunu anakarta yüklemesi gerekmektedir. Böylece ihtiyaç doğrultusunda hangi birimin kiminle ne şekilde etkileşime gireceğini ve nasıl çalışacağını sadece anakart bilecektir.

Bu senaryoda, CDDriver’a takılan bir CD’de ki verilerin CPU’ya aktarılıp ardından ses ve ekran kartlarına ayrıştırılması süreçlerini Mediator tasarım deseniyle modelliyor olacağız. CDDriver ile CD’den alınan/okunan verileri anakart CPU’ya gönderip, işletecektir. Bunun için CDDriver’ın anakarta durumunun değiştiğini bildirmesi yeterli olacaktır. Aynı şekilde CPU aldığı verileri video ve ses verilerine bölüştürerek anakart vasıtasıyla ekran ve ses kartlarına gönderecektir. Yine bu işlem için CPU’nun da anakarta durumunun değiştiğini bildirmesi gerekecektir. Nihai olarak, anakart vasıtasıyla CD’de ki veriler ekran ve ses kartlarına ulaşmış ve işlenmiş olacaktır.

Aktörler & Roller
Anakart Mediator
CDDriver Colleague
Ses Kartı Colleague
Ekran Kartı Colleague
SENARYO 1 ÇÖZÜM

İşte bu kadar… Şimdi 2. senaryoya geçebiliriz.

SENARYO 2
Şehirler arası nakliye firmalarını düşünelim. Örneğin; Iğdır’dan Edirne’ye taşınacak bir ailenin eşyalarını nakliye edebilmek için üç farklı şehirde aktarmalı lojistik firmaları görev alıyor olsun.

Iğdır’dan Sıvas’a “X Firma”sı,
Sivas’tan Ankara’ya “Y Firma”sı ve
Ankara’dan Edirne’ye “Z Firması” nakliye operasyonunda bulunuyor olsun.

Aktörler & Roller
Nakliye Mediator
X Firma Colleague
Y Firma Colleague
Z Firma Colleague
SENARYO 2 ÇÖZÜM

Evet… İşte böyle 🙂 Hadi gelin, hazır ısınmışken bir sonraki senaryoyu inceleyelim.

SENARYO 3
Bu senaryomuzda bir konut alım satım sürecindeki para transferini ele alıyor olacağız. Yapılan antlaşma neticesinde; alıcı, emlakçı ve ev sahibi arasında yapılacak olan para transferi şu şekilde gerçekleşecektir;
Alıcı, eğer konutun fiyatı 100.000 TL’den büyükse parayı satıcıya gönderecek ve ardından satıcı emlakçıya %3’lük komisyonu cebinden verecek.. Yok eğer konutun fiyatı 100.000 TL’den küçükse alıcı, emlakçının %10’luk komisyonunu cebinden verecek ve biryandan da konutun tam parasını satıcıya gönderecektir.

Normal şartlarda bu operasyonu nesneler arasında birebir iletişim kurarak gerçekleştirmeye çalışmak Suriye meselesinden hallice olacaktır. İşte burada Mediator deseni biçilmiş kaftandır.

Aktörler & Roller
Transfer Mediator
Alıcı Colleague
Emlakçı Colleague
Satıcı Colleague
SENARYO 3 ÇÖZÜM

İşte bu kadar…

Haliyle Mediator tasarım desenini pratik açıdan yeterince ele aldık kanaatindeyim.

Şimdi gelin konuyu teoride toparlayarak makalemizi noktalayalım.

Mediator Nerelerde Uygulanmalı?

Mediator Deseninin Artıları ve Eksileri Nelerdir?

Artıları Eksileri
Nesneler arasındaki ilişkiler tek bir yerden(Mediator) yönetileceği için her nesne kendi sorumluluğuna odaklanabilir. Böylece Tek Sorumluluk Prensibi/Single Responsibility Principle sağlanmış olunmakta ve ilgili sınıf tasarımının anlaşılabilirliği artarak, bakımı kolaylaşmaktadır. Zamanla Mediator sınıfı, çok fazla iş/sorumluluk yükleneceği ve haddinden fazla davranış yöneteceği için ister istemez bir Tanrı Nesnesine(God Object) dönüşebilir.
Mevcut nesneleri değiştirmeye gerek kalmaksızın uygulamaya yeni nesneler dahil edilebilir. Böylece değişime kapalı lakin gelişime açık olacak şekilde bir tasarım söz konusu olduğundan dolayı Açık Kapalı Prensibi/Open Closed Principle desteklenmektedir. Mediator deseni aşırı merkezileşme sağlar. Haliyle Mediator sorumluluğunu üstlenecek olan sınıf oldukça yönetilmesi ve sürdürülmesi zor bir sınıf olacaktır.
Geliştirilen bir kodda çeşitli nesneler arasındaki ilişkiyi ve somut bağlantıları Mediator sayesinde azaltabilir ve böylece yönetilebilirlik açısından daha kaliteli kodlar geliştirebilirsiniz.
Her bir nesne esasında bağımsız bir davranış sergileyeceğinden dolayı tek başına da rahatlıkla kullanılabilmektedir.
Nesneler arasında Gevşek Bağlılık(Loose Coupling) söz konusu olmaktadır.

Veritabanındaki many to many ilişkiler Cross Table ile sağlanmaktadır. Aynı mantıkla class’lar da da bu sorumluluğu Mediator sınıfı üstlenmektedir.

Mediator İle Benzer Desenler

Mediator ile Facade Benzerliği
Fark ettiniz mi bilmiyorum ama Facade Design Pattern(Facade Tasarım Deseni) ile Mediator oldukça birbirlerine benzemektedirler. Her ikiside birbirlerine sıkı sıkıya bağlı olan birçok nesne arasındaki diyaloğu düzenlemeye çalışmaktadırlar.

İkisinin arasındaki temel fark;

Facade; nesnelerin alt sistemlerine basitleştirilmiş bir arayüz sağlar. Alt sistemin kendisi Facade arayüzünden habersizdir. Alt sistem içerisinde tüm nesneler doğrudan birbirleriyle iletişim kurabilirler.
Mediator; nesneler(sistemler) arasında iletişim merkezidir. Nesneler yalnızca Mediator nesnesini bilir ve birbirleriyle doğrudan iletişim kurmazlar.

Mediator ile Observer Benzerliği
Mediator ile bir diğer benzerlik gösteren desen ise Observer Design Pattern(Observer Tasarım Deseni)dir. Hatta çoğu durumda aralarındaki farkı anlamak neredeyse imkansız olabileceği için birbirlerinin yerine kullanılabilmektedirler.

Bu iki desen arasındaki ince nüens aşağıdaki gibidir;

Mediator’ın birincil amacı nesneler arasındaki karşılıklı bağımlılıkları ortadan kaldırmaktır. Bunun için bu nesneleri tek bir Mediator nesneye bağımlı hale getiririz.
Observer’ın amacı ise bazı nesneler ile onlara bağlı olan diğer nesneler arasında dinamik tek yönlü bağlantıyı kurmaktır.

Evet… Böylece bu makalenin de sonuna gelmiş bulunmaktayız. Umarım sizin açınızdan aydınlatıcı bilgiler sunabilmişimdir. Sıkılmadan, usanmadan bu satırlara kadar ulaşabilen değerli okuyucularıma en içten teşekkürlerimi sunarım.

İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Örnek senaryo kodlarını indirebilmek için buraya tıklayınız.

Mobil sürümden çık