Menu
Coddy logo textTech

Wzorzec adaptera

Część sekcji Programowanie obiektowe ścieżki GO w Coddy. Lekcja 92 z 107.

Wzorzec Adapter umożliwia współpracę niekompatybilnych interfejsów poprzez opakowanie istniejącego typu w nowy interfejs. Podczas gdy Command enkapsuluje działania, Adapter tłumaczy jeden interfejs na inny, którego oczekują klienci.

Wyobraź sobie, że masz starszą drukarkę, która używa innej sygnatury metody niż ta, której oczekuje Twoja aplikacja:

// Interfejs docelowy używany przez Twoją aplikację
type Printer interface {
    Print(text string) string
}

// Starsza drukarka z niezgodnym interfejsem
type OldPrinter struct{}

func (o OldPrinter) PrintDocument(doc string, copies int) string {
    return fmt.Sprintf("Old printer: %s (x%d)", doc, copies)
}

Adapter opakowuje starszy typ i implementuje oczekiwany interfejs:

type OldPrinterAdapter struct {
    oldPrinter OldPrinter
}

func (a OldPrinterAdapter) Print(text string) string {
    return a.oldPrinter.PrintDocument(text, 1)
}

Teraz stara drukarka działa bezproblemowo z kodem oczekującym interfejsu Printer:

func PrintMessage(p Printer, msg string) string {
    return p.Print(msg)
}

adapter := OldPrinterAdapter{oldPrinter: OldPrinter{}}
result := PrintMessage(adapter, "Hello")  // "Old printer: Hello (x1)"

Wzorzec Adapter jest nieoceniony podczas integrowania bibliotek innych firm, pracy ze starszym kodem lub gdy musisz użyć istniejących klas, które nie spełniają wymagań Twojego interfejsu. Działa jak most, nie modyfikując oryginalnego kodu.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system odtwarzacza multimedialnego z użyciem wzorca Adapter! Masz nowoczesny odtwarzacz audio, który oczekuje ujednoliconego interfejsu, ale musisz zintegrować starszy sprzęt audio, który używa zupełnie innych sygnatur metod. Twój adapter wypełni tę lukę, umożliwiając staremu sprzętowi bezproblemową współpracę z nowym systemem.

Rozmieścisz swój kod w trzech plikach:

  • player.go: Zdefiniuj docelowy interfejs i starsze urządzenie audio.

    Utwórz interfejs AudioPlayer, którego oczekuje nowoczesny system, z metodą Play(track string) string, która przyjmuje nazwę utworu i zwraca komunikat o odtwarzaniu.

    Zdefiniuj także starsze urządzenie, które nie pasuje do tego interfejsu:

    • Struktura VinylPlayer z polem SpeedRPM (int). Ma metodę DropNeedle(record string, side string) string, która zwraca Playing [record] ([side] side) at [speed]rpm

    Interfejs VinylPlayer jest niezgodny z AudioPlayer. Wymaga dwóch parametrów i używa zupełnie innej nazwy metody.

  • adapter.go: Utwórz adapter, który zapewni zgodność starszego urządzenia.

    Zbuduj strukturę VinylAdapter, która opakowuje VinylPlayer i implementuje interfejs AudioPlayer. Gdy wywołana zostanie metoda Play, adapter powinien wywołać metodę DropNeedle odtwarzacza winylowego, domyślnie ustawiając A jako wartość parametru strony.

    Utwórz także nowoczesny odtwarzacz do porównania:

    • Struktura DigitalPlayer: jej metoda Play zwraca Streaming: [track]
  • main.go: Pokaż, że oba odtwarzacze działają przez ten sam interfejs.

    Utwórz funkcję PlayMusic(player AudioPlayer, track string) string, która używa interfejsu do odtwarzania muzyki. Ta funkcja nie powinna wiedzieć ani przejmować się tym, czy używa odtwarzacza cyfrowego, czy odtwarzacza winylowego z adapterem.

    Wczytaj typ odtwarzacza (digital lub vinyl), a jeśli jest to odtwarzacz winylowy, wczytaj także prędkość RPM. Następnie wczytaj nazwę utworu. Utwórz odpowiedni odtwarzacz (używając adaptera dla odtwarzacza winylowego), odtwórz utwór za pomocą funkcji PlayMusic i wypisz wynik.

Podane zostaną następujące dane wejściowe:

  • Linia 1: Typ odtwarzacza (digital lub vinyl)
  • Linia 2: Prędkość RPM (tylko w przypadku odtwarzacza winylowego)
  • Ostatnia linia: Nazwa utworu do odtworzenia

Na przykład, dla danych wejściowych:

digital
Bohemian Rhapsody

Wynik powinien być następujący:

Streaming: Bohemian Rhapsody

A dla danych wejściowych:

vinyl
33
Abbey Road

Wynik powinien być następujący:

Playing Abbey Road (A side) at 33rpm

A dla danych wejściowych:

vinyl
45
Blue Monday

Wynik powinien być następujący:

Playing Blue Monday (A side) at 45rpm

Zwróć uwagę, że funkcja PlayMusic działa identycznie z oboma odtwarzaczami. Nie wie, że odtwarzacz winylowy korzysta w rzeczywistości z adaptera dla zupełnie innego interfejsu. Adapter w tle tłumaczy wywołania nowoczesnego interfejsu na starszy format!

Spróbuj swoich sił

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

// PlayMusic używa interfejsu AudioPlayer do odtwarzania muzyki
// Ta funkcja działa z każdą implementacją AudioPlayer
// TODO: Zaimplementuj tę funkcję tak, aby wywoływała player.Play(track) i zwracała wynik
func PlayMusic(player AudioPlayer, track string) string {
	// TODO: Zaimplementuj tę funkcję
	return ""
}

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	// Odczytaj typ odtwarzacza
	playerType, _ := reader.ReadString('\n')
	playerType = strings.TrimSpace(playerType)
	
	var player AudioPlayer
	var track string
	
	if playerType == "vinyl" {
		// Odczytaj prędkość RPM dla płyty winylowej
		rpmStr, _ := reader.ReadString('\n')
		rpmStr = strings.TrimSpace(rpmStr)
		rpm, _ := strconv.Atoi(rpmStr)
		
		// Odczytaj nazwę utworu
		track, _ = reader.ReadString('\n')
		track = strings.TrimSpace(track)
		
		// TODO: Utwórz VinylPlayer z podaną wartością RPM
		// TODO: Opakuj go w VinylAdapter
		// TODO: Przypisz do zmiennej player
		_ = rpm // Usuń tę linię, gdy zaczniesz używać rpm
	} else {
		// Odczytaj nazwę utworu
		track, _ = reader.ReadString('\n')
		track = strings.TrimSpace(track)
		
		// TODO: Utwórz DigitalPlayer
		// TODO: Przypisz do zmiennej player
	}
	
	// TODO: Wywołaj PlayMusic i wypisz wynik
	_ = player // Usuń tę linię, gdy użyjesz player
	_ = track  // Usuń tę linię, gdy użyjesz track
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Go online