Go'da Neden Kalıtım Yok
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 34 / 107.
Java ve C++ gibi geleneksel nesne yönelimli diller, türler arasında kod paylaşmak için kalıtımı kullanır. Bir alt sınıf, bir üst sınıfı genişleterek tüm alanlarını ve yöntemlerini devralır. Go bu özelliği kasıtlı olarak içermez.
Kalıtım, türler arasında sıkı bağımlılık oluşturur. Bir üst sınıf değiştiğinde, tüm alt sınıflar etkilenir.
Derin kalıtım hiyerarşilerini anlamak ve sürdürmek zorlaşır. "kırılgan temel sınıf sorunu", bir temel sınıfta yapılan değişikliklerin türetilmiş sınıfları beklenmedik bir şekilde bozması durumunda ortaya çıkar.
Go'nun tasarımcıları farklı bir yol seçti: kalıtım yerine bileşim. "Bir Dog is an Animal" demek yerine Go, "Bir Dog has Animal benzeri davranışlar" demenizi teşvik eder. Bu ince değişim, daha esnek ve bakımı daha kolay kodlar yazmanızı sağlar.
Go, daha önce öğrendiğiniz iki mekanizma aracılığıyla kodun yeniden kullanılmasını sağlar:
- Interfaces uygulama ayrıntıları olmadan davranış sözleşmelerini tanımlar
- Struct gömme, türlerin diğer türleri içermesine ve onların yöntemlerini yeniden kullanmasına olanak tanır
Bu karşılaştırmayı düşünün. Geleneksel OOP'de class Dog extends Animal yazabilirsiniz. Go'da Animal struct'ını Dog içine gömer ve paylaşılan arayüzleri uygularsınız. Sonuç, türler arasında daha gevşek bir bağ ile benzer işlevselliktir.
Bu bölüm, Go'nun kalıtımın avantajlarını dezavantajları olmadan nasıl elde ettiğini göstererek yapı gömmeyi derinlemesine inceler.
Görev
KolayKalıtım yerine Go'nun bileşim yaklaşımını gösteren bir bildirim sistemi oluşturalım. Sınıf hiyerarşileri yerine arayüzler ve yapı gömme yoluyla davranışları paylaşan türler oluşturacaksınız.
Kodunuzu üç dosyaya ayıracaksınız:
notifier.go: Tek birNotifiermetoduna sahip birNotify(message string) stringarayüzü tanımlayın. Ayrıca, diğer türler tarafından gömülecek birBaseNotifieralanına sahipNameyapısını oluşturun.BaseNotifieriçin, bildiricinin adını köşeli parantezler içinde mesajın önüne ekleyerek döndürenFormat(message string) stringadlı bir metot tanımlayın.channels.go:BaseNotifieryapısını gömen veNotifierarayüzünü uygulayan iki bildirim kanalı türü oluşturun:- Ek olarak
EmailNotifieralanına sahipAddress - Ek olarak
SMSNotifieralanına sahipPhone
Notifymetodu, gömülüFormatmetodunu kullanmalı ve çıktıya kendine özgü kanal bilgilerini eklemelidir.- Ek olarak
main.go: Herhangi birSendAlertve bir mesaj kabul eden, ardındanNotifierçağrısının sonucunu döndürenNotifyadlı bir işlev oluşturun. Bildirim ayrıntılarını girdiden okuyun, her iki bildirimci türünü de oluşturun ve arayüz üzerinden birbirlerinin yerine nasıl kullanılabileceklerini gösterin.
Aşağıdaki girdiler sağlanacaktır:
- 1. satır: E-posta için bildirimci adı
- 2. satır: E-posta adresi
- 3. satır: SMS için bildirimci adı
- 4. satır: Telefon numarası
- 5. satır: Uyarı mesajı
Format üzerindeki BaseNotifier metodunuz şunu döndürmelidir:
[Name] messageNotify metotlarınız şunları döndürmelidir:
- EmailNotifier:
Email to [Address]: [formatted message] - SMSNotifier:
SMS to [Phone]: [formatted message]
Örneğin, Alerts, user@mail.com, Urgent, 555-1234 ve Server down verildiğinde çıktınız şöyle olmalıdır:
Email to user@mail.com: [Alerts] Server down
SMS to 555-1234: [Urgent] Server downHer iki bildirimci türünün de gömme yoluyla Format içindeki BaseNotifier metodunu yeniden kullandığına, ancak her birinin kendi Notify uygulamasını sağladığına dikkat edin. SendAlert işlevi, somut türü bilmeden herhangi bir Notifier ile çalışır. Bu, kalıtım yerine bileşimin uygulamadaki hâlidir.
Kendin dene
package main
import (
"bufio"
"fmt"
"os"
)
// SendAlert herhangi bir Notifier ve bir mesaj kabul eder, Notify çağrısının sonucunu döndürür
// TODO: SendAlert fonksiyonunu uygula
func main() {
scanner := bufio.NewScanner(os.Stdin)
// E-posta bildirimcisinin adını oku
scanner.Scan()
emailName := scanner.Text()
// E-posta adresini oku
scanner.Scan()
emailAddress := scanner.Text()
// SMS bildirimcisinin adını oku
scanner.Scan()
smsName := scanner.Text()
// Telefon numarasını oku
scanner.Scan()
phoneNumber := scanner.Text()
// Uyarı mesajını oku
scanner.Scan()
alertMessage := scanner.Text()
// TODO: emailName ve emailAddress ile bir EmailNotifier oluştur
// TODO: smsName ve phoneNumber ile bir SMSNotifier oluştur
// TODO: alertMessage'ı her iki bildirimci üzerinden göndermek için SendAlert kullan
// ve sonuçları yazdır
// Kullanılmayan değişken uyarılarını bastır (değişkenleri kullandığında bunları kaldır)
_ = emailName
_ = emailAddress
_ = smsName
_ = phoneNumber
_ = alertMessage
}
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 PoolKendi başına pratik yap: Online Go derleyicisi