Örtük Uygulama
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 26 / 107.
Java veya C# gibi birçok nesne yönelimli dilde, implements gibi anahtar kelimeler kullanarak bir türün bir arayüzü uyguladığını açıkça belirtmeniz gerekir. Go farklı bir yaklaşım benimser: arayüz uygulaması örtüktür (implicit).
Bir tür, sadece tüm metotlarını uygulayarak bir arayüzü karşılar. İlişkiyi herhangi bir yerde beyan etmeye gerek yoktur. Derleyici bunu otomatik olarak anlar.
type Writer interface {
Write(data string) int
}
type FileWriter struct {
Filename string
}
// FileWriter, Writer arayüzünü örtük olarak uygular
func (f FileWriter) Write(data string) int {
fmt.Println("Writing to", f.Filename)
return len(data)
}
FileWriter üzerinde implements Writer bildirimi olmadığına dikkat edin. FileWriter, arayüz imzasıyla eşleşen bir Write(data string) int metoduna sahip olduğu için, otomatik olarak Writer arayüzünü karşılar.
Bu tasarımın güçlü bir sonucu vardır: arayüzleri türler zaten mevcut olduktan sonra tanımlayabilirsiniz. Eğer üçüncü taraf bir kütüphanenin ihtiyacınız olan metotlara sahip bir türü varsa, orijinal kodu değiştirmeden, bu türün halihazırda karşıladığı bir arayüz oluşturabilirsiniz.
func Save(w Writer, content string) {
w.Write(content)
}
func main() {
fw := FileWriter{Filename: "data.txt"}
Save(fw, "Hello!") // FileWriter, Writer arayüzünü karşıladığı için çalışır
}
Örtük uygulama, Go kodunu ayrık ve esnek tutar. Türlerin arayüzler hakkında önceden bilgi sahibi olması gerekmez, bu da sistemleri bağımsız parçalardan oluşturmayı kolaylaştırır.
Görev
KolayGo'de türlerin arayüzleri (interfaces) nasıl örtük olarak (implicitly) karşıladığını gösteren bir mesaj teslimat sistemi kuralım. Herhangi bir ilişkiyi açıkça belirtmeden, aynı arayüzü karşılayan farklı haberci (messenger) türleri oluşturacaksınız.
Kodunuzu iki dosya halinde düzenleyeceksiniz:
messengers.go: Tek birSend(message string) stringmetoduna sahip birMessengerarayüzü tanımlayın. Ardından bu arayüzü örtük olarak karşılayacak iki yapı (struct) oluşturun:Addressalanına (string) sahipEmailMessengerPhoneNumberalanına (string) sahipSMSMessenger
Sendmetoduna sahip olmalıdır. Hiçbir yapıMessengerarayüzünü uyguladığını açıkça beyan etmemelidir; Go, metod imzalarına dayanarak bunu otomatik olarak anlayacaktır.main.go: Herhangi birMessengerve bir mesaj dizesi kabul eden, ardındanSendmetodunu çağırmanın sonucunu döndürenDeliverMessageadında bir fonksiyon oluşturun. Girişten iletişim bilgilerini okuyun, her iki haberci türünü de oluşturun ve her biri aracılığıyla mesajları iletmek için fonksiyonunuzu kullanın.
Aşağıdaki girişler sağlanacaktır:
- Satır 1: E-posta adresi
- Satır 2: Telefon numarası
- Satır 3: Gönderilecek mesaj
Send metodlarınız şu formatlarda dizeler döndürmelidir:
- EmailMessenger:
Email to [Address]: [message] - SMSMessenger:
SMS to [PhoneNumber]: [message]
Örneğin, alice@example.com, 555-1234 ve Hello! verildiğinde, çıktınız şu şekilde olmalıdır:
Email to alice@example.com: Hello!
SMS to 555-1234: Hello!Buradaki temel nokta, DeliverMessage fonksiyonunuzun herhangi bir Messenger kabul etmesi ve hem EmailMessenger hem de SMSMessenger yapılarının sadece eşleşen bir Send metoduna sahip olarak bu arayüzü karşılamasıdır. Hiçbir yerde implements anahtar kelimesi yoktur; Go'nun örtük uygulaması (implicit implementation) her şeyi halleder.
Kopya kağıdı
Go'da arayüz (interface) uygulaması örtüktür (implicit). Bir tür, yalnızca tüm metodlarını uygulayarak bir arayüzü karşılar; açık bir bildirime gerek yoktur.
type Writer interface {
Write(data string) int
}
type FileWriter struct {
Filename string
}
// FileWriter örtük olarak Writer'ı uygular
func (f FileWriter) Write(data string) int {
fmt.Println("Writing to", f.Filename)
return len(data)
}
Herhangi bir implements Writer bildirimi yoktur. FileWriter, arayüz imzasıyla eşleşen bir Write(data string) int metoduna sahip olduğu için Writer arayüzünü otomatik olarak karşılar.
Bir arayüzü karşılayan herhangi bir türü, türün arayüzden haberi olmasına gerek kalmadan kullanabilirsiniz:
func Save(w Writer, content string) {
w.Write(content)
}
func main() {
fw := FileWriter{Filename: "data.txt"}
Save(fw, "Hello!") // FileWriter, Writer'ı karşıladığı için çalışır
}
Bu tasarım, türler zaten mevcut olduktan sonra arayüzler tanımlamanıza olanak tanıyarak kodun bağımsız (decoupled) ve esnek olmasını sağlar.
Kendin dene
package main
import (
"bufio"
"fmt"
"os"
)
// YAPILACAK: Herhangi bir Messenger'ı ve bir mesaj dizesini kabul eden,
// ardından Send çağrısının sonucunu döndüren bir DeliverMessage fonksiyonu oluşturun
func main() {
reader := bufio.NewReader(os.Stdin)
// E-posta adresini oku
email, _ := reader.ReadString('\n')
email = email[:len(email)-1]
// Telefon numarasını oku
phone, _ := reader.ReadString('\n')
phone = phone[:len(phone)-1]
// Mesajı oku
message, _ := reader.ReadString('\n')
if len(message) > 0 && message[len(message)-1] == '\n' {
message = message[:len(message)-1]
}
// YAPILACAK: E-posta adresiyle bir EmailMessenger oluşturun
// YAPILACAK: Telefon numarasıyla bir SMSMessenger oluşturun
// YAPILACAK: Mesajı her bir messenger aracılığıyla göndermek için DeliverMessage'ı kullanın
// ve sonuçları 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