Şablon Metot Kalıbı
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 94 / 107.
Şablon Yöntemi deseni, bir algoritmanın iskeletini temel türde tanımlar ve alt türlerin genel yapıyı değiştirmeden belirli adımları geçersiz kılmasına olanak tanır. Decorator, nesneleri sarmalayarak davranış eklerken Şablon Yöntemi algoritmanın akışını kontrol eder ve tek tek adımların özelleştirilmesine izin verir.
Go'da kalıtım olmadığı için bu kalıbı, yapı gömme özelliğini arayüzlerle birleştirerek uygularız. "template" yapısı algoritmanın yapısını tanımlar ve özelleştirilebilen yöntemleri çağırır:
type DataProcessor interface {
ReadData() string
ProcessData(data string) string
SaveData(result string) string
}
type BaseProcessor struct {
Impl DataProcessor
}
func (b *BaseProcessor) Execute() string {
data := b.Impl.ReadData()
result := b.Impl.ProcessData(data)
return b.Impl.SaveData(result)
}Somut uygulamalar, algoritma akışı değişmeden her adımın kendi sürümünü sağlar:
type CSVProcessor struct{}
func (c CSVProcessor) ReadData() string { return "csv-data" }
func (c CSVProcessor) ProcessData(d string) string { return "processed-" + d }
func (c CSVProcessor) SaveData(r string) string { return "Saved: " + r }
type JSONProcessor struct{}
func (j JSONProcessor) ReadData() string { return "json-data" }
func (j JSONProcessor) ProcessData(d string) string { return "parsed-" + d }
func (j JSONProcessor) SaveData(r string) string { return "Stored: " + r }Şablon methodu Execute, adımları sabit bir sırayla düzenler:
csvProc := &BaseProcessor{Impl: CSVProcessor{}}
fmt.Println(csvProc.Execute()) // Kaydedildi: processed-csv-data
jsonProc := &BaseProcessor{Impl: JSONProcessor{}}
fmt.Println(jsonProc.Execute()) // Saklandı: parsed-json-dataTemplate Method, aynı yapıyı paylaşan ancak belirli adımlarda farklılık gösteren algoritmalara sahip olduğunuzda idealdir; örneğin veri içe/dışa aktarma işlem hatları, rapor oluşturucular veya test çerçeveleri.
Görev
KolayŞablon Method kalıbını kullanarak bir rapor oluşturma sistemi geliştirelim! Farklı rapor türlerinin aynı oluşturma sürecini izlediği; verileri topladığı, biçimlendirdiği ve sonucu çıktı olarak verdiği, ancak her rapor türünün bu adımları farklı şekilde özelleştirdiği bir çerçeve oluşturacaksın.
Kodunu üç dosya arasında düzenleyeceksin:
report.go: Arayüzünü ve rapor oluşturma algoritmasını yöneten temel işlemciyi tanımla.Rapor oluşturma adımlarını temsil eden üç metoda sahip bir
ReportGeneratorarayüzü oluştur:GatherData() string: rapor için ham verileri alırFormatData(data string) string: verileri raporun biçimine dönüştürürOutputReport(formatted string) string: nihai çıktı mesajını oluşturur
Bir
ReportProcessoruygulamasını tutan birReportGeneratoryapısı oluştur. Üç adımı sırayla (topla, biçimlendir, ardından çıktı olarak ver) gerçekleştiren ve nihai sonucu döndüren birGenerate() stringmetodu ekle.generators.go: Her adımı özelleştiren somut rapor oluşturucuları uygula.İki rapor türü oluştur:
SalesReport, birRegionalanına (string) sahipGatherData(),sales-data-[region]değerini döndürürFormatData(data),SALES REPORT: [data]değerini döndürürOutputReport(formatted),Printed: [formatted]değerini döndürür
InventoryReport, birWarehousealanına (string) sahipGatherData(),inventory-[warehouse]değerini döndürürFormatData(data),*** [data] ***değerini döndürürOutputReport(formatted),Exported: [formatted]değerini döndürür
main.go: Aynı algoritma yapısının uygulamaya bağlı olarak nasıl farklı sonuçlar ürettiğini göster.Rapor türünü (
salesveyainventory) ve yapılandırma değerini (sales için bölge, inventory için depo) oku. Uygun oluşturucuyu oluştur, onu birReportProcessoriçine yerleştir,Generate()metodunu çağır ve sonucu yazdır.
Aşağıdaki girdiler sağlanacaktır:
- 1. satır: Rapor türü (
salesveyainventory) - 2. satır: Yapılandırma değeri (bölge adı veya depo adı)
Örneğin, şu verildiğinde:
sales
NorthÇıktın şu olmalıdır:
Printed: SALES REPORT: sales-data-NorthVe şu verildiğinde:
inventory
MainHubÇıktın şu olmalıdır:
Exported: *** inventory-MainHub ***Ve şu verildiğinde:
sales
WestÇıktın şu olmalıdır:
Printed: SALES REPORT: sales-data-WestReportProcessor sınıfının her zaman aynı üç adımı aynı sırayla çağırdığına, ancak her rapor türünün bu adımlar için kendi uygulamasını sağladığına dikkat et. Algoritmanın iskeleti sabit kalırken ayrıntılar değişir: işte Şablon Method kalıbı uygulamada böyle çalışır!
Kendin dene
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Rapor türünü oku
scanner.Scan()
reportType := scanner.Text()
// Yapılandırma değerini oku (bölge veya depo)
scanner.Scan()
configValue := scanner.Text()
// TODO: reportType'a göre uygun generator'ı oluştur
// - Eğer reportType "sales" ise, Region değeri configValue olan bir SalesReport oluştur
// - Eğer reportType "inventory" ise, Warehouse değeri configValue olan bir InventoryReport oluştur
// TODO: generator ile bir ReportProcessor oluştur
// TODO: Generate() metodunu çağır ve sonucu yazdır
_ = reportType
_ = configValue
fmt.Println("TODO: Generate and print the report")
}
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ı11Standart Kütüphane ve OOP
io.Reader ve io.Writersort.Interface Arayüzüfmt.Stringer ArayüzüStruct'lar ile encoding/jsonhttp.Handler ArayüzüÖzet - REST API Modelleri14Tasarım Kalıpları Bölüm 2
Komut KalıbıAdaptör KalıbıDekoratör KalıbıŞablon Metot KalıbıDurum KalıbıKompozit KalıbıDekoratör olarak Middleware3İş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