Gömülü Metotları Gölgeleme
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 39 / 107.
Bazen dış yapının (outer struct), gömülü türün (embedded type) halihazırda sahip olduğu bir metodun kendi uygulamasını sağlamasına ihtiyaç duyarsınız. Buna shadowing (gölgeleme) denir ve yükseltilmiş metodları (promoted methods) özel davranışlarla geçersiz kılmanıza (override) olanak tanır.
Dış yapı (struct) üzerinde, gömülü bir metotla aynı ada sahip bir metot tanımladığınızda, dış metot öncelik kazanır:
type Animal struct {
Name string
}
func (a Animal) Speak() string {
return "Some sound"
}
type Dog struct {
Animal
Breed string
}
func (d Dog) Speak() string {
return "Woof!"
}
Artık bir Dog üzerinde Speak() metodunu çağırdığınızda, dıştaki metot kullanılır:
func main() {
d := Dog{Animal: Animal{Name: "Rex"}, Breed: "Labrador"}
fmt.Println(d.Speak()) // Hav! - Dog'un metodu
fmt.Println(d.Animal.Speak()) // Bir ses - Animal'ın metodu
}
Gömülü (embedded) metot kaybolmaz. Gömülü tür adı aracılığıyla ona hala açıkça erişebilirsiniz. Bu desen, orijinal uygulamayı kullanılabilir tutarken davranışı özelleştirmek istediğinizde, belki de onu geçersiz kılan (overriding) metodunuzun içinden çağırmak için kullanışlıdır:
func (d Dog) Speak() string {
return d.Animal.Speak() + " (but actually Woof!)"
}
Gölgeleme, açık niteleme yoluyla orijinaline erişimi korurken, hangi davranışın sergileneceği üzerinde size kontrol sağlar.
Görev
KolayFarklı bildirim kanallarının mesajları nasıl biçimlendireceğini ve ileteceğini özelleştirebildiği bir bildirim sistemi oluşturalım. Belirli kanalların varsayılan davranışı geçersiz kılmasına (override) izin vermek ve gerektiğinde orijinal uygulamaya hala erişebilmek için metot gölgeleme (method shadowing) kullanacaksınız.
Kodunuzu üç dosya halinde düzenleyeceksiniz:
base.go:TitlevePriorityalanlarına (her ikisi de string) sahip birBaseNotificationyapısı oluşturun. Buna, bildirimi standart bir biçimde döndüren birFormat() stringmetodu verin:[Priority] Title.channels.go:BaseNotificationyapısını gömen (embed) veFormatmetodunu kendi uygulamalarıyla gölgeleyen iki bildirim kanalı türü oluşturun:Recipientalanına sahipEmailNotification—Format()metoduEmail to [Recipient]: [Priority] Titledöndürmelidir.Channelalanına sahipSlackNotification—Format()metodu, gömülü olanBaseNotification.Format()metodunu çağırmalı ve sonucun başına#[Channel]:eklemelidir.
main.go: Girdiden bildirim ayrıntılarını okuyun, her iki bildirim türünü de oluşturun ve şunları yazdırarak gölgelemeyi gösterin:EmailNotification'ın biçimlendirilmiş çıktısı (kendi gölgelenmiş metodunu kullanarak)EmailNotification'ın temel biçimi (gömülü metodu açıkça çağırarak)SlackNotification'ın biçimlendirilmiş çıktısı (dahili olarak temel metodu kullanan)
Aşağıdaki girdiler sağlanacaktır:
- Satır 1: Bildirim başlığı
- Satır 2: Öncelik seviyesi
- Satır 3: E-posta alıcısı
- Satır 4: Slack kanal adı
Örneğin, Server Alert, HIGH, admin@company.com ve ops-alerts verildiğinde, çıktınız şöyle olmalıdır:
Email to admin@company.com: HIGH Server Alert
[HIGH] Server Alert
#ops-alerts: [HIGH] Server AlertEmailNotification'ın temel biçimlendirmeyi tamamen nasıl değiştirdiğine, SlackNotification'ın ise orijinal metodu çağırıp kanal bağlamı ekleyerek onu nasıl geliştirdiğine dikkat edin. Her iki yaklaşım da metot gölgelemenin etkili bir şekilde kullanılmasının farklı yollarını göstermektedir.
Kopya kağıdı
Dış bir struct üzerinde, gömülü bir türdeki metotla aynı isme sahip bir metot tanımladığınızda, dıştaki metot gömülü metodu gölgeler (geçersiz kılar):
type Animal struct {
Name string
}
func (a Animal) Speak() string {
return "Some sound"
}
type Dog struct {
Animal
Breed string
}
func (d Dog) Speak() string {
return "Woof!"
}
Dış struct üzerindeki metodu çağırırken, dıştaki metot öncelik kazanır:
d := Dog{Animal: Animal{Name: "Rex"}, Breed: "Labrador"}
fmt.Println(d.Speak()) // Woof! - Dog'un metodu
fmt.Println(d.Animal.Speak()) // Some sound - Animal'ın metodu
Gömülü metot, gömülü tür adı kullanılarak açıkça belirtilerek erişilebilir kalmaya devam eder. Orijinal uygulamayı, geçersiz kılan metodun içinden çağırabilirsiniz:
func (d Dog) Speak() string {
return d.Animal.Speak() + " (but actually Woof!)"
}
Kendin dene
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Bildirim başlığını oku
scanner.Scan()
title := scanner.Text()
// Öncelik seviyesini oku
scanner.Scan()
priority := scanner.Text()
// E-posta alıcısını oku
scanner.Scan()
recipient := scanner.Text()
// Slack kanal adını oku
scanner.Scan()
channel := scanner.Text()
// TODO: Temel bildirim, başlık, öncelik ve alıcı ile bir EmailNotification oluşturun
// TODO: Temel bildirim, başlık, öncelik ve kanal ile bir SlackNotification oluşturun
// TODO: EmailNotification'ın biçimlendirilmiş çıktısını yazdırın (gölgelenmiş yöntemini kullanarak)
// TODO: EmailNotification'ın temel biçimini yazdırın (gömülü yöntemi açıkça çağırarak)
// TODO: SlackNotification'ın biçimlendirilmiş çıktısını yazdırın
fmt.Println() // Yer tutucu - uygularken kaldı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