Menu
Coddy logo textTech

Kompozit Kalıbı

Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 96 / 107.

Composite deseni, tekil nesneleri ve nesne gruplarını tek tipte ele almanıza olanak tanır. State deseni davranışı dahili duruma göre değiştirirken, Composite hem yaprakların hem de kapsayıcıların aynı arayüzü paylaştığı ağaç yapıları oluşturur.

Bu desen; dosya sistemleri, organizasyon şemaları veya UI bileşenleri gibi hiyerarşik yapılar için mükemmeldir. Go'da, hem bireysel öğelerin hem de kapsayıcıların uyguladığı ortak bir interface tanımlarız:

type Component interface {
    GetSize() int
}

type File struct {
    Name string
    Size int
}

func (f File) GetSize() int {
    return f.Size
}

Bileşik (konteyner), alt öğeleri barındırır ve onların sonuçlarını bir araya getirerek aynı arayüzü uygular:

type Folder struct {
    Name     string
    Children []Component
}

func (f *Folder) Add(c Component) {
    f.Children = append(f.Children, c)
}

func (f Folder) GetSize() int {
    total := 0
    for _, child := range f.Children {
        total += child.GetSize()
    }
    return total
}

Artık klasörleri iç içe yerleştirebilirsiniz ve GetSize() fonksiyonunu çağırmak, ister tek bir dosya ister tüm bir dizin ağacı olsun, aynı şekilde çalışır:

docs := &Folder{Name: "docs"}
docs.Add(File{Name: "readme.txt", Size: 100})
docs.Add(File{Name: "notes.txt", Size: 50})

root := &Folder{Name: "root"}
root.Add(docs)
root.Add(File{Name: "config.json", Size: 25})

fmt.Println(root.GetSize())  // 175

Composite, parça-bütün hiyerarşilerini temsil etmeniz gerektiğinde ve istemcilerin tekil nesneler ile kompozisyonlara aynı şekilde davranmasını istediğinizde idealdir.

challenge icon

Görev

Kolay

Composite desenini kullanarak bir organizasyon şeması sistemi oluşturalım! Hem bireysel çalışanların hem de departmanların (çalışanları veya diğer departmanları içeren) tek tip olarak ele alınabileceği bir yapı oluşturacaksınız; bu, organizasyonun herhangi bir bölümündeki toplam maaşları hesaplamak için mükemmeldir.

Kodunuzu üç dosya halinde düzenleyeceksiniz:

  • component.go: Hem bireylerin hem de grupların uygulayacağı ortak arayüzü (interface) tanımlayın.

    İki yöntemi olan bir OrgComponent arayüzü oluşturun:

    • GetSalary() int — bu bileşen için toplam maaşı döndürür
    • GetName() string — çalışanın veya departmanın adını döndürür
  • organization.go: Hem yaprak (bireysel çalışan) hem de bileşik (departman) türlerini uygulayın.

    Name (string) ve Salary (int) alanlarına sahip bir Employee yapısı (struct) oluşturun. GetSalary() yöntemi kendi maaşını, GetName() yöntemi ise adını döndürür.

    Name (string) alanına ve OrgComponent öğelerini tutan bir Members dilimine (slice) sahip bir Department yapısı oluşturun. Üye eklemek için bir Add(c OrgComponent) yöntemi ekleyin. GetSalary() yöntemi tüm üyelerin maaşlarının toplamını döndürmeli ve GetName() departman adını döndürmelidir.

  • main.go: Bir organizasyon yapısı oluşturun ve maaşları hesaplayın.

    Çalışan sayısını okuyun. Her çalışan için adını ve maaşını okuyarak Employee örnekleri oluşturun. Ardından departman sayısını okuyun. Her departman için adını ve üye dizini sayısını, ardından bu dizinleri (0 tabanlı, oluşturulma sırasına göre önceden oluşturulmuş çalışanlara veya departmanlara atıfta bulunarak) okuyun.

    Yapıyı oluşturduktan sonra, son bir dizin okuyun ve o bileşenin adını ve toplam maaşını şu formatta yazdırın: [name]: [salary]

Aşağıdaki girdiler sağlanacaktır:

  • Çalışan sayısı, ardından her çalışanın adı ve maaşı ayrı satırlarda
  • Departman sayısı, ardından her departmanın adı, üye sayısı ve üye dizinleri
  • Sorgulanacak son dizin

Örneğin, şu girdi verildiğinde:

3
Alice
50000
Bob
60000
Carol
55000
1
Engineering
3
0
1
2
3

Çıktınız şu olmalıdır:

Engineering: 165000

Ve şu girdi verildiğinde:

4
Alice
50000
Bob
60000
Carol
55000
Dave
70000
2
Dev
2
0
1
QA
2
2
3
4

Çıktınız şu olmalıdır:

QA: 125000

Ve şu girdi verildiğinde:

2
Alice
50000
Bob
60000
0
1

Çıktınız şu olmalıdır:

Bob: 60000

GetSalary() yönteminin ister tek bir çalışan ister tüm bir departman üzerinde çağrılsın nasıl aynı şekilde çalıştığına dikkat edin; Composite deseni, bireyleri ve grupları aynı arayüz üzerinden tek tip olarak ele almanıza olanak tanır!

Kopya kağıdı

Composite deseni, tekil nesneleri ve nesne gruplarını ortak bir arayüz aracılığıyla tek tip olarak ele alır. Dosya sistemleri, organizasyon şemaları veya kullanıcı arayüzü (UI) bileşenleri gibi hiyerarşik yapılar için idealdir.

Hem tekil öğelerin hem de kapsayıcıların uyguladığı ortak bir arayüz tanımlayın:

type Component interface {
    GetSize() int
}

Yaprağı (tekil öğe) uygulayın:

type File struct {
    Name string
    Size int
}

func (f File) GetSize() int {
    return f.Size
}

Alt öğeleri tutan ve sonuçlarını birleştiren kompoziti (kapsayıcı) uygulayın:

type Folder struct {
    Name     string
    Children []Component
}

func (f *Folder) Add(c Component) {
    f.Children = append(f.Children, c)
}

func (f Folder) GetSize() int {
    total := 0
    for _, child := range f.Children {
        total += child.GetSize()
    }
    return total
}

Tekil öğelerin ve kompozisyonların tek tip ele alınışını gösteren kullanım örneği:

docs := &Folder{Name: "docs"}
docs.Add(File{Name: "readme.txt", Size: 100})
docs.Add(File{Name: "notes.txt", Size: 50})

root := &Folder{Name: "root"}
root.Add(docs)
root.Add(File{Name: "config.json", Size: 25})

fmt.Println(root.GetSize())  // 175

Kendin dene

package main

import "fmt"

func main() {
	// Çalışan sayısını oku
	var numEmployees int
	fmt.Scanln(&numEmployees)

	// Tüm bileşenleri (çalışanlar ve departmanlar) oluşturulma sırasına göre sakla
	var components []OrgComponent

	// TODO: Her çalışanın adını ve maaşını oku
	// Employee örnekleri oluştur ve bunları components dilimine ekle
	for i := 0; i < numEmployees; i++ {
		var name string
		var salary int
		fmt.Scanln(&name)
		fmt.Scanln(&salary)
		// TODO: Çalışan oluştur ve components'a ekle
	}

	// Departman sayısını oku
	var numDepartments int
	fmt.Scanln(&numDepartments)

	// TODO: Her departmanın adını, üye sayısını ve üye indekslerini oku
	// Department örnekleri oluştur, üyeleri indekse göre ekle ve components'a ekle
	for i := 0; i < numDepartments; i++ {
		var deptName string
		var memberCount int
		fmt.Scanln(&deptName)
		fmt.Scanln(&memberCount)
		// TODO: Departman oluştur, üye indekslerini oku, üyeleri ekle, components'a ekle
	}

	// Sorgulanacak son indeksi oku
	var queryIndex int
	fmt.Scanln(&queryIndex)

	// TODO: Bileşenin adını ve toplam maaşını şu formatta yazdır: [name]: [salary]
	// Örnek: fmt.Printf("%s: %d\n", name, salary)
}
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