Menu
Coddy logo textTech

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.

challenge icon

Görev

Kolay

Gö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: Style alanına (string) ve metni stil ile sarmalayan (örneğin [Style] text [/Style] gibi) bir Format(text string) string metoduna sahip bir Formatter yapı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:
    • Author ve Date alanlarına sahip bir Metadata yapısı — bu, doğrudan erişilebilir olması gereken genel bilgileri temsil eder.
    • Title alanına sahip, Metadata yapısını gömen (yazar ve tarihe doğrudan erişim için) ancak Formatter için toplama kullanan (formatter adında bir alanla dahili bir uygulama detayı olarak) bir Report yapısı.
    Report yapısına, başlığı biçimlendirmek için dahili biçimlendiriciyi kullanan ve meta verileri içeren bir Generate() string metodu ekleyin.
  • main.go: Girdiden rapor detaylarını okuyun, hem gömülü meta verilere hem de toplanmış bir biçimlendiriciye sahip bir Report oluş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:

  1. Rapor üzerinden doğrudan erişilen yazar (gömmenin alanı öne çıkardığını gösterir)
  2. Gömülü tip adı üzerinden erişilen tarih (report.Metadata.Date)
  3. 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-15

Author 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
}
quiz iconKendini test et

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