Menu
Coddy logo textTech

Birden Fazla Struct Gömme

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

Go, farklı kaynaklardan gelen davranışları birleştirerek tek bir struct içine birden fazla struct gömmenize olanak tanır. Bu, diğer dillerdeki çoklu kalıtıma benzer, ancak Go'nun kompozisyon (composition) yaklaşımını kullanır.

type Logger struct{}

func (l Logger) Log(msg string) string {
    return "LOG: " + msg
}

type Notifier struct{}

func (n Notifier) Notify(msg string) string {
    return "NOTIFY: " + msg
}

type Service struct {
    Name string
    Logger
    Notifier
}

Service yapısı artık her iki gömülü türün metotlarına da erişebilir:

func main() {
    s := Service{Name: "OrderService"}
    fmt.Println(s.Log("started"))      // LOG: started
    fmt.Println(s.Notify("new order")) // NOTIFY: new order
}

Birden fazla struct gömerken, iki gömülü türün aynı isme sahip metotları varsa bir isimlendirme çakışması oluşabilir. Go bu belirsizliği otomatik olarak çözmez:

type A struct{}
func (A) Greet() string { return "Hello from A" }

type B struct{}
func (B) Greet() string { return "Hello from B" }

type Combined struct {
    A
    B
}

func main() {
    c := Combined{}
    // c.Greet() - derleme hatası: belirsiz seçici
    fmt.Println(c.A.Greet())  // A'dan merhaba
    fmt.Println(c.B.Greet())  // B'den merhaba
}

Çakışmalar ortaya çıktığında, tür adını bir niteleyici olarak kullanarak hangi gömülü türün metodunu çağırmak istediğinizi açıkça belirtmelisiniz.

challenge icon

Görev

Kolay

Struct gömme (struct embedding) yoluyla birden fazla yeteneği birleştiren bir akıllı ev cihaz sistemi inşa edelim. Ayrı denetleyici türlerini gömerek hem aydınlatmayı kontrol edebilen hem de müzik çalabilen bir cihaz oluşturacaksınız.

Kodunuzu üç dosya halinde düzenleyeceksiniz:

  • controllers.go: Farklı yetenekler sağlayan iki bağımsız denetleyici struct'ı oluşturun:
    • Bir Brightness alanına (int) ve Light set to [level]% döndüren bir SetLight(level int) string metoduna sahip LightController.
    • Bir Volume alanına (int) ve Volume set to [level]% döndüren bir SetVolume(level int) string metoduna sahip AudioController.
    Her iki denetleyici de bir Status() string metoduna sahip olmalıdır; bu, yönetmeniz gereken bir isimlendirme çakışması yaratacaktır. LightController.Status() metodu Brightness: [Brightness]% döndürmeli ve AudioController.Status() metodu Volume: [Volume]% döndürmelidir.
  • device.go: Hem LightController hem de AudioController'ı gömen, Name alanına sahip bir SmartDevice struct'ı oluşturun. Her bir gömülü türün Status() metodunu açıkça çağırarak belirsizliği gideren ve cihaz adıyla birlikte her iki denetleyici durumunu döndüren FullStatus() string adlı bir metot ekleyin.
  • main.go: Girişten cihaz yapılandırmasını okuyun, bir SmartDevice oluşturun, ışık ve ses seviyelerini ayarlamak için yükseltilmiş (promoted) metotları kullanın ve ardından tam durumu görüntüleyin.

Aşağıdaki girişler sağlanacaktır:

  • Satır 1: Cihaz adı
  • Satır 2: Başlangıç parlaklık seviyesi (tam sayı)
  • Satır 3: Başlangıç ses seviyesi (tam sayı)
  • Satır 4: Ayarlanacak yeni parlaklık seviyesi (tam sayı)
  • Satır 5: Ayarlanacak yeni ses seviyesi (tam sayı)

FullStatus() metodunuz şunu döndürmelidir:

[Name] - [LightController.Status()], [AudioController.Status()]

SetLight ve SetVolume (gömülü türlerden yükseltilen) çağrılarının sonuçlarını yazdırın, ardından tam durumu yazdırın.

Örneğin, Living Room Hub, 50, 30, 75 ve 60 verildiğinde, çıktınız şöyle olmalıdır:

Light set to 75%
Volume set to 60%
Living Room Hub - Brightness: 75%, Volume: 60%

SetLight ve SetVolume metotlarının metot yükseltme (method promotion) yoluyla SmartDevice üzerinden doğrudan erişilebilir olduğuna, ancak her iki gömülü tür de bu metoda sahip olduğu için Status() metodunun açıkça belirtilmesi gerektiğine dikkat edin.

Kopya kağıdı

Go, tek bir struct içinde birden fazla struct gömülmesine (embedding) izin vererek farklı kaynaklardan gelen davranışları kompozisyon yoluyla birleştirmenizi sağlar:

type Logger struct{}

func (l Logger) Log(msg string) string {
    return "LOG: " + msg
}

type Notifier struct{}

func (n Notifier) Notify(msg string) string {
    return "NOTIFY: " + msg
}

type Service struct {
    Name string
    Logger
    Notifier
}

Service struct'ı, her iki gömülü türün metodlarına da erişebilir:

s := Service{Name: "OrderService"}
fmt.Println(s.Log("started"))      // LOG: started
fmt.Println(s.Notify("new order")) // NOTIFY: new order

İsim çakışmaları, gömülü türlerin aynı isme sahip metodları olduğunda meydana gelir. Hangi gömülü türün metodunun çağrılacağını açıkça belirtmeniz gerekir:

type A struct{}
func (A) Greet() string { return "Hello from A" }

type B struct{}
func (B) Greet() string { return "Hello from B" }

type Combined struct {
    A
    B
}

// c.Greet() - derleme hatası: ambiguous selector
c := Combined{}
fmt.Println(c.A.Greet())  // Hello from A
fmt.Println(c.B.Greet())  // Hello from B

Kendin dene

package main

import (
	"fmt"
)

func main() {
	// Girdiyi oku
	var name string
	fmt.Scanln(&name)

	var initialBrightness int
	fmt.Scanln(&initialBrightness)

	var initialVolume int
	fmt.Scanln(&initialVolume)

	var newBrightness int
	fmt.Scanln(&newBrightness)

	var newVolume int
	fmt.Scanln(&newVolume)

	// TODO: Verilen isim ve başlangıç değerleri ile bir SmartDevice oluşturun

	// TODO: Üst sınıftan gelen SetLight metodunu kullanın ve sonucu yazdırın

	// TODO: Üst sınıftan gelen SetVolume metodunu kullanın ve sonucu yazdırın

	// TODO: FullStatus() metodunu kullanarak tam durumu yazdırın
}
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