Adaptör Kalıbı
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 92 / 107.
Adapter deseni, mevcut bir türü yeni bir arayüzle sarmalayarak uyumsuz arayüzlerin birlikte çalışmasını sağlar. Command eylemleri kapsüllerken, Adapter bir arayüzü istemcilerin beklediği başka bir arayüze dönüştürür.
Uygulamanızın beklediğinden farklı bir metot imzası kullanan eski bir yazıcınız olduğunu hayal edin:
// Uygulamanızın kullandığı hedef arayüz (interface)
type Printer interface {
Print(text string) string
}
// Uyumsuz arayüze sahip eski yazıcı
type OldPrinter struct{}
func (o OldPrinter) PrintDocument(doc string, copies int) string {
return fmt.Sprintf("Old printer: %s (x%d)", doc, copies)
}Adaptör, eski türü sarmalar ve beklenen arayüzü uygular:
type OldPrinterAdapter struct {
oldPrinter OldPrinter
}
func (a OldPrinterAdapter) Print(text string) string {
return a.oldPrinter.PrintDocument(text, 1)
}Artık eski yazıcı, Printer arayüzünü bekleyen kodlarla sorunsuz bir şekilde çalışır:
func PrintMessage(p Printer, msg string) string {
return p.Print(msg)
}
adapter := OldPrinterAdapter{oldPrinter: OldPrinter{}}
result := PrintMessage(adapter, "Hello") // "Old printer: Hello (x1)"Adapter deseni; üçüncü taraf kütüphaneleri entegre ederken, eski kodlarla çalışırken veya arayüz gereksinimlerinize uymayan mevcut sınıfları kullanmanız gerektiğinde paha biçilemezdir. Orijinal kodu değiştirmeden bir köprü görevi görür.
Görev
KolayAdapter desenini kullanarak bir medya oynatıcı sistemi oluşturalım! Birleşik bir arayüz bekleyen modern bir ses oynatıcınız var, ancak tamamen farklı metot imzaları kullanan eski ses ekipmanlarını entegre etmeniz gerekiyor. Adaptörünüz bu boşluğu dolduracak ve eski donanımın yeni sistemle sorunsuz bir şekilde çalışmasını sağlayacaktır.
Kodunuzu üç dosya halinde düzenleyeceksiniz:
player.go: Hedef arayüzünüzü ve eski bir ses cihazını tanımlayın.Modern sisteminizin beklediği, bir parça adı alan ve bir oynatma mesajı döndüren
Play(track string) stringmetoduna sahip birAudioPlayerarayüzü oluşturun.Ayrıca bu arayüzle eşleşmeyen eski bir cihaz tanımlayın:
SpeedRPMalanına (int) sahipVinylPlayeryapısı — bu yapı,Playing [record] ([side] side) at [speed]rpmdöndüren birDropNeedle(record string, side string) stringmetoduna sahiptir.
VinylPlayer'ın arayüzü AudioPlayer ile uyumsuzdur; iki parametre gerektirir ve tamamen farklı bir metot adı kullanır.
adapter.go: Eski cihazı uyumlu hale getiren adaptörünüzü oluşturun.Bir
VinylPlayernesnesini sarmalayan veAudioPlayerarayüzünü uygulayan birVinylAdapteryapısı oluşturun.Playçağrıldığında, adaptör plak çalarınDropNeedlemetodunu çağırmalı ve side parametresi için varsayılan olarak"A"değerini kullanmalıdır.Karşılaştırma için modern bir oynatıcı da oluşturun:
DigitalPlayeryapısı —PlaymetoduStreaming: [track]döndürür.
main.go: Her iki oynatıcının da aynı arayüz üzerinden çalıştığını gösterin.Müzik çalmak için arayüzü kullanan bir
PlayMusic(player AudioPlayer, track string) stringfonksiyonu oluşturun; bu fonksiyon dijital bir oynatıcı mı yoksa uyarlanmış bir plak çalar mı kullandığını bilmemeli veya umursamamalıdır.Bir oynatıcı türü (
"digital"veya"vinyl") okuyun ve eğer vinyl ise RPM hızını da okuyun. Ardından parça adını okuyun. Uygun oynatıcıyı oluşturun (vinyl için adaptörü kullanarak), parçayıPlayMusicfonksiyonunuz aracılığıyla oynatın ve sonucu yazdırın.
Aşağıdaki girdiler sağlanacaktır:
- Satır 1: Oynatıcı türü (
"digital"veya"vinyl") - Satır 2: RPM hızı (sadece vinyl ise)
- Son satır: Oynatılacak parça adı
Örneğin, şu girdi verildiğinde:
digital
Bohemian RhapsodyÇıktınız şu olmalıdır:
Streaming: Bohemian RhapsodyVe şu girdi verildiğinde:
vinyl
33
Abbey RoadÇıktınız şu olmalıdır:
Playing Abbey Road (A side) at 33rpmVe şu girdi verildiğinde:
vinyl
45
Blue MondayÇıktınız şu olmalıdır:
Playing Blue Monday (A side) at 45rpmPlayMusic fonksiyonunun her iki oynatıcıyla da nasıl aynı şekilde çalıştığına dikkat edin; plak çaların aslında tamamen farklı bir arayüzden uyarlandığına dair hiçbir fikri yoktur. Adaptör, modern arayüz çağrılarını perde arkasında eski formata dönüştürür!
Kopya kağıdı
Adapter (Adaptör) deseni, mevcut bir türü yeni bir arayüzle sarmalayarak uyumsuz arayüzlerin birlikte çalışmasını sağlar.
Uygulamanızın beklediği bir hedef arayüz (interface) tanımlayın:
type Printer interface {
Print(text string) string
}Uyumsuz bir arayüzü olan eski (legacy) bir tür:
type OldPrinter struct{}
func (o OldPrinter) PrintDocument(doc string, copies int) string {
return fmt.Sprintf("Old printer: %s (x%d)", doc, copies)
}Eski türü sarmalayan ve hedef arayüzü uygulayan bir adaptör oluşturun:
type OldPrinterAdapter struct {
oldPrinter OldPrinter
}
func (a OldPrinterAdapter) Print(text string) string {
return a.oldPrinter.PrintDocument(text, 1)
}Eski türün hedef arayüzü bekleyen kodla çalışmasını sağlamak için adaptörü kullanın:
func PrintMessage(p Printer, msg string) string {
return p.Print(msg)
}
adapter := OldPrinterAdapter{oldPrinter: OldPrinter{}}
result := PrintMessage(adapter, "Hello") // "Old printer: Hello (x1)"Adapter deseni, üçüncü taraf kütüphaneleri entegre etmek, eski kodlarla çalışmak veya mevcut sınıfları orijinal kodu değiştirmeden gerekli arayüzlere uydurmak için kullanışlıdır.
Kendin dene
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
// PlayMusic, müzik çalmak için AudioPlayer arayüzünü kullanır
// Bu fonksiyon herhangi bir AudioPlayer uygulamasıyla çalışır
// TODO: player.Play(track) metodunu çağırmak ve sonucu döndürmek için bu fonksiyonu uygulayın
func PlayMusic(player AudioPlayer, track string) string {
// TODO: Bu fonksiyonu uygulayın
return ""
}
func main() {
reader := bufio.NewReader(os.Stdin)
// Oynatıcı türünü oku
playerType, _ := reader.ReadString('\n')
playerType = strings.TrimSpace(playerType)
var player AudioPlayer
var track string
if playerType == "vinyl" {
// Plak için RPM hızını oku
rpmStr, _ := reader.ReadString('\n')
rpmStr = strings.TrimSpace(rpmStr)
rpm, _ := strconv.Atoi(rpmStr)
// Parça adını oku
track, _ = reader.ReadString('\n')
track = strings.TrimSpace(track)
// TODO: Verilen RPM ile bir VinylPlayer oluşturun
// TODO: Bunu bir VinylAdapter içine sarın
// TODO: player değişkenine atayın
_ = rpm // rpm kullandığınızda bu satırı kaldırın
} else {
// Parça adını oku
track, _ = reader.ReadString('\n')
track = strings.TrimSpace(track)
// TODO: Bir DigitalPlayer oluşturun
// TODO: player değişkenine atayın
}
// TODO: PlayMusic fonksiyonunu çağırın ve sonucu yazdırın
_ = player // player kullandığınızda bu satırı kaldırın
_ = track // track kullandığınızda bu satırı kaldı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ı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 Pool