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.
Görev
KolayStruct 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
Brightnessalanına (int) veLight set to [level]%döndüren birSetLight(level int) stringmetoduna sahipLightController. - Bir
Volumealanına (int) veVolume set to [level]%döndüren birSetVolume(level int) stringmetoduna sahipAudioController.
Status() stringmetoduna sahip olmalıdır; bu, yönetmeniz gereken bir isimlendirme çakışması yaratacaktır.LightController.Status()metoduBrightness: [Brightness]%döndürmeli veAudioController.Status()metoduVolume: [Volume]%döndürmelidir.- Bir
device.go: HemLightControllerhem deAudioController'ı gömen,Namealanına sahip birSmartDevicestruct'ı oluşturun. Her bir gömülü türünStatus()metodunu açıkça çağırarak belirsizliği gideren ve cihaz adıyla birlikte her iki denetleyici durumunu döndürenFullStatus() stringadlı bir metot ekleyin.main.go: Girişten cihaz yapılandırmasını okuyun, birSmartDeviceoluş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
}
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