Gömme vs Agregasyon
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 38 / 107.
Gömmenin (embedding), alanları ve metotları dış yapıya (outer struct) yükselttiğini öğrendiniz. Ancak Go, başka bir yapıyı (struct) isimlendirilmiş bir alan olarak dahil ettiğiniz toplama (aggregation) yöntemini de destekler. Her bir yaklaşımın ne zaman kullanılacağını anlamak, iyi bir tasarımın anahtarıdır.
Gömme (embedding) ile alan adını atlarsınız ve iç türün üyeleri doğrudan erişilebilir hale gelir:
type Writer struct{}
func (w Writer) Write() string { return "writing" }
type Document struct {
Writer // gömme - alan adı yok
}
d := Document{}
d.Write() // doğrudan erişim
Toplama (aggregation) ile alana açık bir isim verirsiniz ve iç türe erişmek için bu ismin kullanılmasını zorunlu kılarsınız:
type Document struct {
writer Writer // toplama (aggregation) - isimlendirilmiş alan
}
d := Document{writer: Writer{}}
d.writer.Write() // alan ismi kullanılmalıdır
Temel fark, ifade ettiğiniz ilişkidir. Gömme (Embedding), dış türün iç türün kimliğini üstlendiği bir "is-a" ilişkisini ifade eder. Toplama (Aggregation) ise dış türün yalnızca iç türü barındırdığı bir "has-a" ilişkisini ifade eder.
Dış tipin, iç tip tarafından uygulanan arayüzleri karşılamasını istediğinizde veya doğrudan metot erişimi API'yi daha temiz hale getirdiğinde embedding kullanın. İç tipin dışarıya açılmaması gereken bir uygulama detayı olduğu durumlarda veya iç tipe nasıl erişileceği üzerinde açık bir kontrol istediğinizde aggregation kullanın.
Görev
KolayGömme (embedding) ile toplama (aggregation) yöntemlerinin ne zaman kullanılacağını gösteren bir rapor oluşturma sistemi kuralım. Bazı bileşenlerin doğrudan erişilebilir olması gerektiği (gömme), bazılarının ise dahili uygulama detayları olarak kalması gerektiği (toplama) bir sistem oluşturacaksınız.
Kodunuzu üç dosya halinde düzenleyeceksiniz:
formatter.go:Stylealanına (string) ve metni stil ile sarmalayan (örneğin[Style] text [/Style]gibi) birFormat(text string) stringmetoduna sahip birFormatteryapısı oluşturun. Bu, doğrudan dışarıya açılmaması gereken dahili bir yardımcı olacaktır.report.go: Rapor oluşturmayı farklı şekilde ele alan iki yapı oluşturun:AuthorveDatealanlarına sahip birMetadatayapısı — bu, doğrudan erişilebilir olması gereken genel bilgileri temsil eder.Titlealanına sahip,Metadatayapısını gömen (yazar ve tarihe doğrudan erişim için) ancakFormatteriçin toplama kullanan (formatteradında bir alanla dahili bir uygulama detayı olarak) birReportyapısı.
Reportyapısına, başlığı biçimlendirmek için dahili biçimlendiriciyi kullanan ve meta verileri içeren birGenerate() stringmetodu ekleyin.main.go: Girdiden rapor detaylarını okuyun, hem gömülü meta verilere hem de toplanmış bir biçimlendiriciye sahip birReportoluşturun. Rapordaki yazara doğrudan erişerek (gömme yoluyla) ve ardından biçimlendirilmiş raporu oluşturarak (dahili olarak gizli biçimlendiriciyi kullanan) aradaki farkı gösterin.
Aşağıdaki girdiler sağlanacaktır:
- Satır 1: Rapor başlığı
- Satır 2: Yazar adı
- Satır 3: Tarih
- Satır 4: Biçimlendirici stili
Format metodunuz şunu döndürmelidir:
[Style] text [/Style]Generate metodunuz şunu döndürmelidir:
[formatted title]
Author: [Author], Date: [Date]Ana dosyanızda üç satır yazdırın:
- Rapor üzerinden doğrudan erişilen yazar (gömmenin alanı öne çıkardığını gösterir)
- Gömülü tip adı üzerinden erişilen tarih (
report.Metadata.Date) Generate()çağrısının sonucu
Örneğin, Quarterly Results, Jane Doe, 2024-01-15 ve BOLD verildiğinde çıktınız şöyle olmalıdır:
Jane Doe
2024-01-15
[BOLD] Quarterly Results [/BOLD]
Author: Jane Doe, Date: 2024-01-15Author ve Date alanlarına gömme yoluyla doğrudan Rapor üzerinden nasıl erişilebildiğine, ancak biçimlendiricinin nasıl gizli kaldığına dikkat edin — report.Format() metodunu doğrudan çağıramazsınız çünkü isimlendirilmiş bir alanla toplanmıştır. Bu, uygulamada "is-a" (bir ...'dır) ile "has-a" (bir ...'ya sahiptir) ilişkisi arasındaki farkı gösterir.
Kopya kağıdı
Go, bir yapıyı (struct) diğerinin içine dahil etmek için iki yol sunar: gömme (embedding) ve toplama (aggregation).
Gömme (Embedding), alan adını atlayarak iç türün alanlarını ve metotlarını dış yapıya yükseltir (promote):
type Writer struct{}
func (w Writer) Write() string { return "writing" }
type Document struct {
Writer // embedding - no field name
}
d := Document{}
d.Write() // direct access to embedded method
Toplama (Aggregation), açık bir alan adı kullanır ve iç türe erişmek için bu adın kullanılmasını gerektirir:
type Document struct {
writer Writer // aggregation - named field
}
d := Document{writer: Writer{}}
d.writer.Write() // must use field name
Hangisi ne zaman kullanılmalı:
- Gömme (Embedding): Bir "is-a" (bir ...-dır) ilişkisini ifade eder. Dış türün iç türün arayüzlerini (interface) karşılaması gerektiğinde veya doğrudan metot erişimi API'yi iyileştirdiğinde kullanın.
- Toplama (Aggregation): Bir "has-a" (bir ...-ya sahiptir) ilişkisini ifade eder. İç türün ifşa edilmemesi gereken bir uygulama detayı olduğu durumlarda veya erişim üzerinde açık kontrol istediğinizde kullanın.
Gömme ile, gerekirse alanlara gömülü tür adı üzerinden hala erişebilirsiniz:
type Metadata struct {
Author string
}
type Report struct {
Metadata // embedded
}
r := Report{Metadata: Metadata{Author: "Jane"}}
r.Author // direct access via promotion
r.Metadata.Author // explicit access via type name
Kendin dene
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
title := scanner.Text()
scanner.Scan()
author := scanner.Text()
scanner.Scan()
date := scanner.Text()
scanner.Scan()
style := scanner.Text()
// TODO: Yazar ve tarihi içeren bir Metadata yapısı (struct) oluşturun
// TODO: Verilen stile sahip bir Formatter oluşturun
// TODO: Metadata'yı gömen (embed) ve Formatter'ı birleştiren (aggregate) bir Report oluşturun
// TODO: Report üzerinden doğrudan erişilen yazarı yazdırın (gömme işlemi alanı yükseltir)
// TODO: Gömülü tip adı üzerinden erişilen tarihi yazdırın (report.Metadata.Date)
// TODO: Generate() çağrısının sonucunu yazdırın
// Kullanılmayan değişken uyarılarını bastırın (değişkenleri kullandığınızda bunları kaldırın)
_ = title
_ = author
_ = date
_ = style
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1Go OOP Temelleri
Harici DosyalarGo Çalışma Alanı ve ModüllerPaketler ve İçe AktarmalarDışa Aktarılan ve Aktarılmayan İsimlerGo'da OOP'ye GirişSınıf Olarak Struct'larStruct'larda Metot TanımlamaPointer ve Değer AlıcılarStruct BaşlatmaYapıcı FonksiyonlarÖzet - Basit Hesap Makinesi4Arayüzler
Arayüzlere GirişÖrtük UygulamaSözleşme Olarak ArayüzBoş Arayüz (any)Tür OnaylamaTür SeçimiArayüz BileşimiStringer ve Error ArayüzleriÖzet - Şekil Hesaplayıcı7Kapsülleme
Dışa Aktarılan ve Aktarılmayan AlanlarPaket Seviyesinde KapsüllemeGetter ve Setter MetotlarıGo'da Bilgi GizlemeÖzet - Öğrenci Kayıtları10Generics (Go 1.18+)
Generics'e GirişTür ParametreleriTür KısıtlamalarıGeneric Struct'larGeneric Metotlar İçin Geçici ÇözümÖzet - Generic Koleksiyon13Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıAbstract Factory KalıbıObserver KalıbıStrategy Kalıbı2Türler ve Struct'lar: Derinlemesine İnceleme
Temel ve Bileşik TürlerÖzel Tür TanımlamalarıStruct EtiketleriAnonim Struct'larİç İçe Geçmiş Struct'larSıfır Değerler ve VarsayılanlarÖzet - Rehber5Kalıtım Yerine Kompozisyon
Go'da Neden Kalıtım YokStruct Gömme TemelleriMetot YükseltmeBirden Fazla Struct GömmeGömme vs AgregasyonGömülü Metotları GölgelemeÖzet - Çalışan Hiyerarşisi8Hata Yönetimi ve OOP
error ArayüzüÖzel Hata TürleriHata Sarmalama (fmt.Errorf)Sentinel Hatalarerrors.Is() ve errors.As()Panic, Defer ve RecoverÖzet - Dosya Ayrıştırıcı3İşaretçiler ve Bellek
Go'da İşaretçi TemelleriStruct İşaretçileriDeğer ile Geçme ve Referans ile Geçmenew() FonksiyonuGo'da Garbage CollectionÖzet - Linked List Oluşturucu6Go'da Polimorfizm
Interface'ler ile PolimorfizmGo'da Duck TypingInterface Karşılama KurallarıPolimorfik KoleksiyonlarDependency InjectionÖzet - Payment Processor9Eşzamanlılık ve OOP
Goroutine TemelleriKanallar ve İletişimTamponlu ve Tamponsuz KanallarSelect İfadesisync.Mutex ve sync.RWMutexsync.WaitGroupThread-Safe Struct TasarımıÖzet - Worker Pool