Go'da Duck Typing
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 42 / 107.
ördek tiplemesi terimi şu deyişten gelir: "Bir ördek gibi yürüyorsa ve bir ördek gibi vaklıyorsa, o bir ördektir." Go'da bu, bir türün bir interface uyguladığını açıkça belirtmesine gerek olmadığı anlamına gelir. Yalnızca doğru metotlara sahip olması yeterlidir.
Bu arayüzü ve tamamen ilgisiz iki türü düşünün:
type Quacker interface {
Quack() string
}
type Duck struct{}
func (d Duck) Quack() string { return "Quack!" }
type Robot struct{}
func (r Robot) Quack() string { return "Beep-quack!" }
Ne Duck ne de Robot tanımlamalarında herhangi bir yerde Quacker'dan bahseder. Buna rağmen ikisi de, doğru imzaya sahip bir Quack() metoduna sahip oldukları için arayüzü karşılar:
func MakeItQuack(q Quacker) {
fmt.Println(q.Quack())
}
func main() {
MakeItQuack(Duck{}) // Vak!
MakeItQuack(Robot{}) // Bip-vak!
}
Bu örtük uyumluluk güçlüdür, çünkü türler zaten var olduktan sonra arayüzler tanımlamanıza olanak tanır. Kaynak kodlarını değiştirmeden harici paketlerdeki türlerle eşleşen bir arayüz oluşturabilirsiniz. Türlerin arayüzünüzü bilmesi gerekmez. Yalnızca doğru şekilde davranmaları gerekir.
Go'da ördek tipleme, derleme zamanı tür güvenliğini korurken dinamik dillerin esnekliğini sunar. Derleyici, türlerin arayüz değerleri olarak kullanılmasına izin vermeden önce gerekli yöntemlere gerçekten sahip olduklarını doğrular.
Görev
KolayÖrdek tiplemesinin işleyişini gösteren bir mesajlaşma sistemi oluşturalım. Hiçbiri uyguladığını açıkça bildirmeden, ortak bir arayüz üzerinden mesaj gönderebilen tamamen ilgisiz türler oluşturacaksın.
Kodunu üç dosyaya ayıracaksın:
messengers.go: Aynı davranışı tesadüfen paylaşan, birbiriyle ilgisiz üç yapı oluştur:Phone, birNumberalanına sahip olacak.SendMessage(text string) stringmetoduSMS to [Number]: [text]döndürecek.Computer, birEmailalanına sahip olacak.SendMessage(text string) stringmetoduEmail to [Email]: [text]döndürecek.Pigeon, birNamealanına sahip olacak.SendMessage(text string) stringmetodu[Name] carries: [text]döndürecek.
sender.go: BirMessengermetodu gerektiren birSendMessage(text string) stringarayüzü tanımla. BirBroadcastdilimi ve bir mesaj dizesi alan, ardından her messenger üzerindeMessengerçağrısının sonucunu içeren bir dize dilimi döndürenSendMessageadlı bir işlev oluştur.main.go: Ayrıntıları girdiden oku, her messenger türünden bir tane oluştur, bunları birMessengerdiliminde topla ve tüm messenger'lar üzerinden bir mesaj göndermek içinBroadcastişlevini kullan. Her sonucu kendi satırında yazdır.
Aşağıdaki girdiler sağlanacak:
- 1. satır: Telefon numarası
- 2. satır: E-posta adresi
- 3. satır: Güvercin adı
- 4. satır: Yayınlanacak mesaj
Örneğin 555-1234, alice@mail.com, Winston ve Hello World verildiğinde çıktın şöyle olmalı:
SMS to 555-1234: Hello World
Email to alice@mail.com: Hello World
Winston carries: Hello WorldBuradaki temel fikir, Phone, Computer ve Pigeon'ın hiçbir ortak yönünün olmamasıdır. Ortak bir temel türü paylaşmazlar ve Messenger'ı açıkça uygulamazlar. Yine de hepsi aynı şekilde "vakladığı" için (eşleşen metoda sahip oldukları için) Go, hepsinin Messenger değerleri olarak kullanılmasına izin verir. İşte ördek tiplemesi budur.
Kendin dene
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Telefon numarasını oku
scanner.Scan()
phoneNumber := scanner.Text()
// Read email address
scanner.Scan()
email := scanner.Text()
// Güvercin adını oku
scanner.Scan()
pigeonName := scanner.Text()
// Yayınlanacak mesajı oku
scanner.Scan()
message := scanner.Text()
// TODO: Her bir haberci türünden bir tane oluştur (Phone, Computer, Pigeon)
// TODO: Tüm habercileri bir Messenger diliminde topla
// TODO: Mesajı tüm haberciler aracılığıyla göndermek için Broadcast kullan
// TODO: Her sonucu kendi satırına yazdır
// Değişkenleri kullanmak için yer tutucu (uygularken kaldır)
_ = phoneNumber
_ = email
_ = pigeonName
_ = message
}
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