Design Patterns & Golang: Flyweight 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

Filmlere ve dizilere karşı hobisi olan maddi durumu yerinde bir insansınız. İzlediğiniz filmler ve diziler hakkında başka insanlarla konuşmayı, uzun uzun teoriler yapmayı çok istiyorsunuz. Bu vesileyle de sizinle aynı zevklere sahip insanların olduğu bir gruba girdiniz. Ancak size kötü bir haberim var. Piranaların içine düştünüz çünkü bu gruptaki herkes pintiliğin kitabını yazmış.

Tanıştığınız herkes sizden online yayın platformlarından birisi için hesabınızı rica ediyor. Siz de kişisel hesabınızı dağıtmak istemiyorsunuz ama sevaptır diyip rica eden kişi için bir üyelik daha açıyorsunuz. Bir başkası geliyor, onun için de aynısını yapıyorsunuz. Bir bakmışsınız 10 tane hesabın aylık ücretini ödemeye başlamışsınız. Bu yük artık size ağır gelmeye başlıyor.

Sonra birden kafanızın üstünde bir ampul yanıyor. Diyor ki ben enayi miyim herkese hesap alıyorum? Diğer insanlara vermek için bir hesap açayım. İsteyen herkese de onun bilgilerini vereyim. Hepsi aynı hesabı kullansın. Bu şekilde hem herkesi mutlu etmiş oluyorsunuz, hem de teoriler üretmek için bir sürü arkadaşınız olmuş oluyor.

Problem

  • Herkes için hesap açmanın maliyetli olması
  • Arkadaşınız olmaması

Çözüm

  • Herkese aynı hesap bilgilerinin verilmesi
  • Sizi parasız da sevecek arkadaşlar bulunması

Teknik Giriş

Hemen başta söyleyeyim. Arkadaşla ilgili olan madde patternden bağımsız, yüzünüzü gülümsetmek içindi. Kodların içinde nasıl arkadaş bulabileceğinize dair bir yöntem yok maalesef :(

Onun dışında hikayemizi modellemeye başlayabiliriz. Öncelikle kısaca Online yayın platformlarının uygulamasını istediğimiz arayüzümüzü tanımlıyoruz.

type Hesap interface {
GirisYap()
}

Açıkça görülebileceği üzere içerisinde sadece GirisYap() fonksiyonunu barındırmasını bekliyorum. Bunu uygulayan platform nesnelerimizi de hızlıca aradan çıkaralım çünkü fonksiyonlarının içerisinde sadece bilgilendirici bir mesaj barındıracaklar.

type Netflix struct{}

func (n *Netflix) GirisYap() {
fmt.Println("Netflix'e giriliyor")
}
type DisneyPlus struct{}

func (n *DisneyPlus) GirisYap() {
fmt.Println("Disney+'a giriliyor")
}
type BluTV struct{}

func (n *BluTV) GirisYap() {
fmt.Println("BluTV'ye giriliyor")
}

Şimdi de bunları satın alan insan objemizin yapısını kuralım. İnanın bana bütün olay burada bitiyor.

type Insan struct {
hesaplar map[string]Hesap
}

func (i *Insan) HesabiniRicaEt(platform string) Hesap {
if i.hesaplar[platform] != nil {
return i.hesaplar[platform]
}

switch platform {
case "Netflix":
i.hesaplar[platform] = &Netflix{}
return i.hesaplar[platform]
case "Disney+":
i.hesaplar[platform] = &DisneyPlus{}
return i.hesaplar[platform]
case "BluTV":
i.hesaplar[platform] = &BluTV{}
return i.hesaplar[platform]
}

return nil
}

Insan objem, içerisinde sahip olduğu hesapları barındırabileceği bir Map tutuyor. Eğer Daha önceden sahipse direkt olarak veriyi dönüyor. Eğer daha önceden sahip değilse de uygun case’e girerek objeyi oluşturuyor. Hikayeye göre konuşursak da satın alıyor. Örnek kodumuza bakarak çalışıp çalışmadığını test edelim.

func OrnekCalistir() {
var hesap Hesap

Ali := &Insan{
hesaplar: make(map[string]Hesap),
}
fmt.Printf("Ali'nin Hesapları: %v\n", Ali.hesaplar)

for i := 0; i < 3; i++ {
hesap = Ali.HesabiniRicaEt("Netflix")
hesap.GirisYap()
}
fmt.Printf("Ali'nin Hesapları: %v\n", Ali.hesaplar)

for i := 0; i < 4; i++ {
hesap = Ali.HesabiniRicaEt("Disney+")
hesap.GirisYap()
}
fmt.Printf("Ali'nin Hesapları: %v\n", Ali.hesaplar)

for i := 0; i < 5; i++ {
hesap = Ali.HesabiniRicaEt("BluTV")
hesap.GirisYap()
}
fmt.Printf("Ali'nin Hesapları: %v", Ali.hesaplar)
}

En başta Insan objemden bir nesne oluşturuyorum ve bunun adına Ali diyorum. Programın başında alinin hesabı yok ve log’da hesabının olmadığını görmemiz gerekiyor. Sonrasında 3 adet kişi Ali’den Netflix hesabı rica ediyor ve hemen giriş yapıp keyfini sürmeye başlıyor.

Hatırlarsanız hikayenin sonuna doğru akıllanmıştık. Bu nedenle ilk gelen istekten sonra satın aldığı netflix’i diğer isteyenlere de vermeye başladık. Aynı durum 4 kişiyle Disney+ için ve daha sonrasında da 5 kişiyle BluTV için yaşanıyor. Günün sonunda Ali’nin 3 adet hesabının olmasını ve isteyen herkese aynı hesapları dönmüş olmasını bekliyoruz. Hadi o zaman çıktıyı inceleyelim:

Ali’nin Hesapları: map[]
Netflix’e giriliyor
Netflix’e giriliyor
Netflix’e giriliyor
Ali’nin Hesapları: map[Netflix]
Disney+’a giriliyor
Disney+’a giriliyor
Disney+’a giriliyor
Disney+’a giriliyor
Ali’nin Hesapları: map[Disney+, Netflix]
BluTV’ye giriliyor
BluTV’ye giriliyor
BluTV’ye giriliyor
BluTV’ye giriliyor
BluTV’ye giriliyor
Ali’nin Hesapları: map[BluTV, Disney+, Netflix]

Sonuç

Artık bu dizaynın ne gibi problemlere çözüm getirdiğini biliyorsunuz. Gerçek hayatta maddi konuları çözdüğü gibi bilgisayar için de maddiyat’a varabilen kaynak kullanımı sorununu çözüyor. Çok da karmaşık olmamasına rağmen oldukça etkili bir pattern ama siz yine de arkadaşlarınızı dikkatli seçin.

--

--