Design Patterns & Golang: Mediator Pattern

Arda Coşar
4 min readJun 20, 2023

--

Giriş

Selamlar, design pattern yazı serimde özellikle gerçek hayattan basit örnekler seçmeye çalışıyorum. Çünkü sektörün içinden olsun diye seçilen karmaşık örnekler, hakim olmadığınız terimleri barındırabileceğinden ana fikrin anlaşılmasını zorlaştırabiliyor. Ayrıca sektördeki kullanım alanlarını vermenin kişiyi, pattern’i anlamaktan çok ezbere ittiğini düşünüyorum.

Hedefim, patternleri kullanmanız gerektiği yerlerde problemi tanımanız ve çözümü kendi şartlarınıza göre uyarlayabilecek seviyeye gelmeniz olacak.

Hikaye

Her öğrencinin tutkusu doğrultusunda bir kulüp açarak liderlik edebildiği ya da daha önceden açılmış kulüplere kayıt olabileceği bir okulda lise zamanlarınızı yaşıyorsunuz. Bu okulda sistem henüz tam oturtulmamış. Eğer bir kulüp açacaksanız ya da bir kulübe katılacaksanız sizi çok iş bekliyor.

Diyelim ki bir kulüp açmak istiyorsunuz ve üye toplamaya karar verdiniz. Bu da okuldaki her öğrenciyle tek tek konuşup sizle aynı hobiye sahip kişileri ararken yorgunluktan bayılmanız anlamına geliyor. Ayrıca sadece belli başlı öğrencilerle konuşmak istiyorsanız da tüm öğrenciler hakkında bilgiye sahip olmalısınız. Yoksa konuşmak istediğiniz tipteki öğrencileri filtreden geçiremezsiniz.

Şayet bir kulübe katılmak istediğinizde de benzer bir durumla karşılaşacaksınız. Her öğrenciyle konuşmaya çalışıp hobinize uygun kulüp bulmaya çalışacaksınız. Size uygun hobileri olabilecek öğrencileri ayıklamaya çalışmak için de tüm öğrenciler hakkında bilgiye sahip olmanız gerekecektir.

En sonunda müdür öğrencilerin bu çaresizliğine dayanamaz ve paraya kıyar. Okulun girişinde herkesin görebileceği bir duvara Okul Panosu asar. Der ki: “Bundan sonra kulüp açanlar bu panoya kulüp bilgilerini ve numarasını içeren bir kağıt eklesin. Kulüp arayanlar da istedikleri zaman gelip panoyu kontrol etsin. Birbirinizi darlamayın gençler…” Klasik müdür işte, atarını yapacak. Biz yine de kendisine teşekkür edelim. Çünkü artık tek bir yerden bu süreç yönetilecek ve herkesin herkesle tek tek iletişime geçmesine gerek kalmayacak.

Problem

  • Her öğrencinin her öğrenciyle ilgili bilgiye ihtiyaç duyması
  • Her öğrencinin her öğrenciyle iletişime geçmek zorunda olması

Çözüm

  • Merkezi bir yerden sürecin yönetilmesi
  • Öğrencilere sadece panonun nerede olduğunun bildirilmesi

Teknik Giriş

Oldukça popüler bir tasarım olan Mediator ile yine karşınızdayım. Bu yüzden fazla laf kalabalığı yapmadan hızlıca hikayeyi modellemeye geçebiliriz. Önce basit yapıları aradan çıkaralım. Mesela panoya astığımız duyuruları temsil edecek yapıyı oluşturabiliriz.

type Duyuru struct {
Aciklama string
IletisimNo string
}

Kısa ve sade. İçinde sadece bilgilendirme için açıklama ve iletişim kurulabilmesi için telefon numarası barındırıyor. Asıl olaylar bu objeyi içinde barındıran Pano ve Öğrenci yapımızda gerçekleşiyor. Pano ile başlayacak olursak

type OkulPanosu struct {
duyurular []Duyuru
}

func (op *OkulPanosu) PanoyaEkle(duyuru Duyuru) {
op.duyurular = append(op.duyurular, duyuru)
fmt.Println("Duyuru panoya asıldı.")
}

func (op *OkulPanosu) UygunDuruyuGetir(ogrenci Ogrenci) *Duyuru {
for _, duyuru := range op.duyurular {
if strings.Contains(duyuru.Aciklama, ogrenci.Hobi) {
return &duyuru
}
}
return nil
}

Gördüğünüz üzere içinde duyuruların bir listesini tutuyor. Panoya ekle adındaki fonksiyonumuz kendisine verilen argümanı, içindeki listeye ekleyen dümdüz bir işleve sahip olarak karşımıza çıkıyor.

type Ogrenci struct {
Ad string
OkulNumarasi string
Hobi string
Pano *OkulPanosu
}

Bir de Öğrenci tipinde veri bekleyen UygunDuruyuGetir adında bir fonksiyon var. Öğrencilerin okula kayıt olurken seçtikleri hobiler var. UygunDuruyuGetir fonksiyonunda Duyurular içerisinde geziyor ve açıklamalarında öğrencinin hobisine dair bir kelime geçiyor mu diye kontrol ediyor. Buna uygun bir duyuru bulursa de geriye bu duyuruyu döndürüyor.

Öğrenci yapısına biraz odaklanalım. Farkettiyseniz içinde OkulPano’su var. Yani her öğrenci Panonun yerini biliyor demek oluyor. Bu bilgiyle beraber öğrenci yapısının fonksiyonlarını inceleyebiliriz.

func (o *Ogrenci) DuyuruYayimla(duyuru Duyuru) {
fmt.Println(o.Ad, "bir duyuru yayımlıyor. Duyuru:", duyuru.Aciklama)
o.Pano.PanoyaEkle(duyuru)
}

func (o *Ogrenci) DuyurularaGozat() {
duyuru := o.Pano.UygunDuruyuGetir(*o)
if duyuru != nil {
fmt.Println(o.Ad, "kendine uygun duyuruyu buldu. Duyuru:", duyuru.Aciklama)
} else {
fmt.Println(o.Ad, "kendine uygun bir duyuru bulamadı")
}
}

DuyuruYayımla adında, verilen değeri panoya ekleyen çok basit bir fonksiyon barındırıyor. Hemen altında da Panoya göz atabilmemiz için DuyurularaGozat adında bir fonksiyon barındırıyor. Sonrasında buradan gelen veriye göre hareket ediyor.

Son olarak da Örnek kodumuza öğrenci oluşturmasının pratik olması için basit bir fonksiyon daha hazırladık.

func YeniOgrenci(ad, okulNo, hobi string, pano *OkulPanosu) Ogrenci {
ogrenci := Ogrenci{
Ad: ad,
OkulNumarasi: okulNo,
Hobi: hobi,
Pano: pano,
}

return ogrenci
}

Ve artık örnek kodumuzu incelemeye başlayabiliriz:

func OrnekCalistir() {
var pano OkulPanosu
var mahmut, turgut, cenk, cansu Ogrenci

turgut = YeniOgrenci("Turgut", "967", "Tiyatro", &pano)
cenk = YeniOgrenci("Cenk", "412", "Futbol", &pano)
cansu = YeniOgrenci("Cansu", "119", "Gitar", &pano)
mahmut = YeniOgrenci("Mahmut", "235", "Tiyatro", &pano)

mahmut.DuyurularaGozat()
cenk.DuyurularaGozat()

turgut.DuyuruYayimla(Duyuru{
Aciklama: "Tiyatro kulübü açıyoruz, katılımcıları bekleriz",
IletisimNo: "0222 222 22 22",
})

cansu.DuyurularaGozat()
mahmut.DuyurularaGozat()
}

Öncelikle örneğim için 4 farklı öğrenci oluşturuyorum ancak bilerek 2 tanesinin hobisini aynı tutuyorum. Hobisi tiyatro olan Mahmut isimli öğrenci panoya göz attığında hiçbir şey bulamaması gerekiyor. Ancak Turgut kulüp açmaya karar verip duyuru yayınladıktan sonra Mahmut Panoyu kontrol etmek isterse bu ilanı farkedecek ve ona göre davranışını belirleyecektir. Bu açıklamaların ışığında çıktıyı inceleyebiliriz:

Mahmut kendine uygun bir duyuru bulamadı
Cenk kendine uygun bir duyuru bulamadı
Turgut bir duyuru yayımlıyor. Duyuru: Tiyatro kulübü açıyoruz, katılımcıları bekleriz
Duyuru panoya asıldı.
Cansu kendine uygun bir duyuru bulamadı
Mahmut kendine uygun duyuruyu buldu. Duyuru: Tiyatro kulübü açıyoruz, katılımcıları bekleriz

Sonuç

Artık bu dizaynın ne gibi problemlere çözüm getirdiğini biliyorsunuz. Dikkat ettiyseniz Mediator görevi gören Pano objemiz, öğrencilerin içerisinde gömülü bir şekilde arabuluculuk yapıyor. Her birinin içine aynı obje yerleştiriliyor. Bu şekilde herkes aynı objeye bağlı verileri güncelleyebiliyor veya rahatça okuyabiliyor. Bu da birbirleriyle haberleşebilmelerini ve uyum içerisinde çalışabilmelerini sağlıyor.

--

--