Design Patterns & Golang: Proxy Pattern

Arda Coşar
3 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

Muz imparatorluğunun kralısınız. Taleplerine kulak açmanız gereken kalabalık bir halkınız var. Bunların hepsini dinleyip çözüm üretmek isteyen iyi kalpli bir yönetici olsanız da gerçek hayat maalesef bu kadar iyimser değil.

Eğer önünüze gelen herkes’i odanıza alırsanız suikast’e çok daha açık olursunuz. Eğer talebi olan bu kadar çok insanın arasında gerçekten önemli kişiler varsa bunları da kaçıracaksınız. Talebini daha önce iletmiş bir kişi her gün gelip sorunum çözüldü mü diye de sorarsa muhtemelen asıl sorumluluklarınızı gerçekleştiremeyecek hale geleceksiniz. Çünkü Kral olarak size düşenden fazlasını yapmaya çalışıyorsunuz.

Bunun yerine size Vekillik yapması için birisini seçebilirsiniz. Talebi olan herkesi bırakın o incelesin. Tehlikeli mi diye kontrol etsin, önemli birisi mi diye kontrol etsin. Eğer çok meşgulseniz önem sırası düşük olanları sıraya alsın vb. Siz de kral olarak asıl işinize odaklanabilirsiniz.

Problem

  • Kralın saldırıya daha açık olması
  • Önemli isteklerin gecikmesi
  • Talebini ilettikten sonra kontrol amaçlı tekrar gelen kişilerin meşgul etmesi

Çözüm

  • Krala gelmeden önce talepleri karşılayacak bir vekil atanması
  • Kötü niyetli kişilerin krala varmadan ayıklanması
  • Taleplerin önem sırasına sokulması
  • Tekrar gelen kişilere hızlıca cevap dönülmesi

Teknik Giriş

Hadi şimdi bu hikayeyi modelleyelim. Öncelikle Kralın ve Vekilin aynı tipte obje olarak görülmesini sağlamamız gerekiyor. Bunun için de onları Dinleyici adında oluşturduğum bir arayüze implemente etmekle başlayabiliriz.

type Dinleyici interface {
Dinle(gorusmeci string)
}

Kral adında bir struct oluşturup kendisine ait bir Dinle fonksiyonu yazıyorum. İçerisinde temsilen ekrana yazı yazan tek satırlık bir kod yazdım. Eğer krala ulaştıysanız sizi dinleyecektir.

type Kral struct {
Isim string
}

func (k Kral) Dinle(gorusmeci string) {
fmt.Println("İsteğini değerlendireceğim", gorusmeci)
}

Aynı işlemi Vekil yapısı için de gerçekleştiriyorum. Onun Dinle fonksiyonunu biraz inceleyeceğiz.

type Vekil struct {
kral Kral
}

func (v Vekil) Dinle(gorusmeci string) {

if strings.Contains(gorusmeci, "Suçlu") {
fmt.Println("Krala ulaşmana izin veremem, ona zarar vermeye çalışabilirsin")
return
}

if strings.Contains(gorusmeci, "Halktan biri") {
fmt.Println("Talebinizi not ettik, kral müsait olduğunda size haber verilecektir")
return
}

if strings.Contains(gorusmeci, "Lord") {
fmt.Println("Hoş geldiniz", gorusmeci)

v.kral.Dinle(gorusmeci)
}
}

Burada konseptin anlaşılması için çok basit kontroller üzerinden gittim. Gelen görüşmecinin Suçlu olduğu anlaşılırsa direkt olarak akıştan çıkılıyor. Buradaki suçlu analojisi cevap vermek istemediğiniz talep türlerini yada talep sahiplerini ifade ediyor.

Gelen görüşmecinin Halktan biri olduğu anlaşılırsa sistemi meşgul etmemek için sıraya alınıyor. Bu örnek bir case olduğu için sıraya alma işlemini implemente etmedim. Buradaki durumlar tamamen sizin keyfinize kalmış. Asıl iş yapılmadan önce neleri kontrol etmek istiyorsanız Proxy nesnenize uygun koşulu yerleştirebilir ve istediğiniz işlemi içerisine kodlayabilirsiniz

Gelen görüşmecinin Lord olduğu anlaşılırsa talebi önemli olabileceğinden direkt olarak krala yönlendiriliyor ve talebi dinleniyor.

Taleplerin geleceği Krallık için de bir obje tanımlayalım

type Krallik struct{}

func (k Krallik) KrallaGorusmeTalepEt(gorusmeci string) {
var dinleyici Dinleyici

// dinleyici = Kral{Isim: "Süleyman"}
dinleyici = Vekil{
kral: Kral{Isim: "Süleyman"},
}

fmt.Println("Kapıya ulaşıldı...")
dinleyici.Dinle(gorusmeci)
}

Burada kişileri direkt Kral’a yönlendirip tüm kontrolleri kaldırmak isterseniz yorum satırındaki kodu kullanacaktınız. Ancak biz araya bir katman daha attığımız için Vekil yapısından bir örnek oluşturup içerisine çok değerli kralımızı veriyoruz. Son olarak hikayemizi gerçekleştirmek için çalıştıracağımız ana kod bloğunu hazırlayabiliriz.

func OrnekCalistir() {
var MuzKralligi Krallik

fmt.Println("------------ Suçlu Talebi --------------")
MuzKralligi.KrallaGorusmeTalepEt("Suçlu Yasin")

fmt.Println("------------ Halk Talebi --------------")
MuzKralligi.KrallaGorusmeTalepEt("Halktan biri Mehmet")

fmt.Println("------------ Lord Talebi --------------")
MuzKralligi.KrallaGorusmeTalepEt("Lord Cenk")
}

Kendi örneklerinizde kimin suçlu, kimin halktan biri ve kimin lord olduğuna siz karar vereceksiniz. Ben ana fikirden uzaklaşmamak adına kişilere sadece lakap ekledim. Örneğimizi çalıştırdığımızda programımızın çıktısı şu şekilde olacaktır:

— — — — — — Suçlu Talebi — — — — — — —
Kapıya ulaşıldı…
Krala ulaşmana izin veremem, ona zarar vermeye çalışabilirsin
— — — — — — Halk Talebi — — — — — — —
Kapıya ulaşıldı…
Talebinizi not ettik, kral müsait olduğunda size haber verilecektir
— — — — — — Lord Talebi — — — — — — —
Kapıya ulaşıldı…
Hoş geldiniz Lord Cenk
İsteğini değerlendireceğim Lord Cenk

Sonuç

Artık bu dizaynın ne gibi problemlere çözüm getirdiğini biliyorsunuz. “Kralın içine if blokları koyarak neden yapmadık?” diyorsanız eğer, cevabım “Çünkü kralın işi bu değil” olurdu. Çünkü burada kralın işi dinlemek; taleplerin ve ziyaretçilerin kontrolünü başkası yapmalıydı. Yapılar olabildiğince soyutlanmalı, sade ve anlaşılır dizayn edilmelidir.

--

--