Polimorfik Koleksiyonlar
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 44 / 107.
Arayüzlerin en güçlü uygulamalarından biri, farklı türleri aynı koleksiyonda saklamaktır. Bir arayüz türündeki slice, o arayüzü karşılayan herhangi bir değeri tutabilir ve bu da ilgili ancak farklı türleri bir arada gruplandırmanıza olanak tanır.
Çeşitli şekilleri yönetmeniz gereken bir senaryo düşünün. Her tür için ayrı dilimler (slice) kullanmak yerine, arayüz (interface) türünde tek bir dilim kullanabilirsiniz:
type Shape interface {
Area() float64
}
type Circle struct{ Radius float64 }
func (c Circle) Area() float64 { return 3.14159 * c.Radius * c.Radius }
type Rectangle struct{ Width, Height float64 }
func (r Rectangle) Area() float64 { return r.Width * r.Height }
func main() {
shapes := []Shape{
Circle{Radius: 5},
Rectangle{Width: 4, Height: 3},
Circle{Radius: 2},
}
for _, s := range shapes {
fmt.Printf("Area: %.2f\n", s.Area())
}
}
shapes dilimi hem daireleri hem de dikdörtgenleri tutar. Yineleme sırasında, her öğe kendi gerçek türüne göre Area() metoduna yanıt verir. Bu, koleksiyonlara uygulanan polimorfizmdir; aynı döngü tüm şekil türlerini tek tip bir şekilde işler.
Çeşitli öğeleri işleyen sistemler oluştururken polimorfik koleksiyonlar temel öneme sahiptir: e-posta ve SMS mesajları gönderen bir bildirim sistemi, farklı düşman türlerini güncelleyen bir oyun veya birden fazla dosya formatını işleyen bir belge işlemcisi. Koleksiyon belirli türlerle ilgilenmez; yalnızca her öğenin gerekli davranışı sağlamasıyla ilgilenir.
Görev
KolayFarklı görev türlerini birleşik bir arayüz üzerinden yöneten bir görev yönetim sistemi oluşturalım. Çeşitli görev türleri oluşturacak ve hepsini polimorfik bir koleksiyon içinde birlikte işleyeceksiniz.
Kodunuzu üç dosya halinde düzenleyeceksiniz:
task.go: BirSummary() stringmetodu gerektiren birTaskarayüzü (interface) tanımlayın. Bu arayüz, tüm görev türlerinin yerine getirmesi gereken ortak sözleşme olacaktır.types.go: Her biriTaskarayüzünü uygulayan üç farklı görev türü oluşturun:ID(string) veSeverity(string) alanlarına sahipBugFix—Summary()metoduBug #[ID] ([Severity])değerini döndürürName(string) vePoints(int) alanlarına sahipFeature—Summary()metoduFeature: [Name] - [Points] ptsdeğerini döndürürTopic(string) alanına sahipDocumentation—Summary()metoduDocs: [Topic]değerini döndürür
main.go: BirTaskdilimi (slice) kabul eden ve her görevin özetini kendi satırında yazdıranPrintBacklogadında bir fonksiyon oluşturun. Görev detaylarını girdiden okuyun, her görev türünden birer tane oluşturun, hepsini tek bir[]Taskdiliminde toplayın ve bunuPrintBacklogfonksiyonuna gönderin.
Aşağıdaki girdiler sağlanacaktır:
- Satır 1: Bug ID
- Satır 2: Bug severity
- Satır 3: Feature name
- Satır 4: Feature points (tam sayı)
- Satır 5: Documentation topic
Örneğin, 1042, critical, Dark Mode, 8 ve API Reference verildiğinde, çıktınız şu şekilde olmalıdır:
Bug #1042 (critical)
Feature: Dark Mode - 8 pts
Docs: API ReferenceBuradaki güç, PrintBacklog fonksiyonunun hatalar, özellikler veya dokümantasyon için ayrı mantıklara ihtiyaç duymamasıdır; sadece dilim üzerinde döner ve her öğe üzerinde Summary() metodunu çağırır. Her görev türü kendi benzersiz formatıyla yanıt verir, bu da polimorfik koleksiyonların farklı türleri tek tipte işlemenize nasıl olanak tanıdığını gösterir.
Kopya kağıdı
Bir arayüz (interface) türündeki dilim (slice), o arayüzü karşılayan herhangi bir değeri tutabilir ve bu da polimorfik koleksiyonlara olanak tanır:
type Shape interface {
Area() float64
}
type Circle struct{ Radius float64 }
func (c Circle) Area() float64 { return 3.14159 * c.Radius * c.Radius }
type Rectangle struct{ Width, Height float64 }
func (r Rectangle) Area() float64 { return r.Width * r.Height }
func main() {
shapes := []Shape{
Circle{Radius: 5},
Rectangle{Width: 4, Height: 3},
Circle{Radius: 2},
}
for _, s := range shapes {
fmt.Printf("Area: %.2f\n", s.Area())
}
}
shapes dilimi, her ikisi de Shape arayüzünü uygulayan farklı türleri (Circle ve Rectangle) tutar. Yineleme sırasında, her öğe kendi gerçek türüne göre Area() metoduna yanıt verir; bu, koleksiyonlara uygulanan polimorfizmdir.
Bu desen, çeşitli öğelerin tek tip bir şekilde işlenmesi için kullanışlıdır: farklı mesaj türlerini işleyen bildirim sistemleri, çeşitli düşman türlerini güncelleyen oyunlar veya birden fazla dosya formatını işleyen belge işlemcileri.
Kendin dene
package main
import (
"fmt"
)
// TODO: Task dilimini (slice) kabul eden ve her bir görevin özetini
// kendi satırında yazdıran bir PrintBacklog fonksiyonu oluşturun
func main() {
// Girdiyi oku
var bugID string
var bugSeverity string
var featureName string
var featurePoints int
var docTopic string
fmt.Scanln(&bugID)
fmt.Scanln(&bugSeverity)
fmt.Scanln(&featureName)
fmt.Scanln(&featurePoints)
fmt.Scanln(&docTopic)
// TODO: Her görev türünden (BugFix, Feature, Documentation) birer tane oluşturun
// TODO: Tüm görevleri tek bir []Task diliminde (slice) toplayın
// TODO: Görev dilimi ile PrintBacklog fonksiyonunu çağı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