Kompozycja interfejsów
Część sekcji Programowanie obiektowe ścieżki GO w Coddy. Lekcja 31 z 107.
Go pozwala tworzyć większe interfejsy przez komponowanie mniejszych. Zamiast definiować jeden duży interfejs z wieloma metodami, osadzasz istniejące interfejsy w definicji nowego interfejsu.
type Reader interface {
Read() string
}
type Writer interface {
Write(data string)
}
// ReadWriter łączy oba interfejsy
type ReadWriter interface {
Reader
Writer
}Interfejs ReadWriter wymaga teraz zarówno metod Read(), jak i Write(). Każdy typ, który implementuje obie metody, spełnia wymagania interfejsu ReadWriter, a także osobno interfejsów Reader i Writer.
type File struct {
Name string
}
func (f File) Read() string { return "file content" }
func (f File) Write(data string) { fmt.Println("Writing:", data) }
func Process(rw ReadWriter) {
content := rw.Read()
rw.Write(content)
}
func main() {
f := File{Name: "data.txt"}
Process(f) // File spełnia interfejs ReadWriter
}To podejście oparte na kompozycji pozwala zachować małe i skoncentrowane interfejsy. Możesz łączyć je według potrzeb, tworząc precyzyjne kontrakty dla swoich funkcji. Biblioteka standardowa Go szeroko wykorzystuje ten wzorzec, na przykład io.ReadWriter, który łączy io.Reader i io.Writer.
Wyzwanie
ŁatwyStwórzmy system odtwarzacza multimedialnego, który demonstruje kompozycję interfejsów. Utworzysz małe, wyspecjalizowane interfejsy, a następnie połączysz je w bardziej rozbudowany interfejs, który może spełniać jeden typ.
Rozmieścisz swój kod w dwóch plikach:
media.go: Zdefiniuj trzy interfejsy i strukturę, która implementuje je wszystkie:- Interfejs
Playerz metodąPlay() string - Interfejs
Recorderz metodąRecord(content string) string - Interfejs
MediaDevice, który łączy interfejsyPlayeriRecorder - Strukturę
SmartDevicez polemName, która implementuje wszystkie wymagane metody
- Interfejs
main.go: Utwórz funkcje demonstrujące, jak można używać tej samej strukturySmartDeviceza pośrednictwem różnych typów interfejsów. Napisz trzy funkcje:UsePlayer, która przyjmujePlayeri wywołuje jego metodęPlayUseRecorder, która przyjmujeRecorderoraz ciąg znaków z treścią, a następnie wywołujeRecordUseMediaDevice, która przyjmujeMediaDeviceoraz ciąg znaków z treścią, a następnie wywołuje zarównoRecord, jak iPlay
SmartDevicei pokaż, jak używać go za pośrednictwem wszystkich trzech typów interfejsów.
Podane zostaną następujące dane wejściowe:
- Wiersz 1: Nazwa urządzenia
- Wiersz 2: Treść do nagrania
Twoje metody powinny zwracać ciągi znaków w następujących formatach:
Play():[Name] is playingRecord(content):[Name] recorded: [content]
Na przykład dla danych MyPhone i voice memo wynik powinien wyglądać następująco:
MyPhone is playing
MyPhone recorded: voice memo
MyPhone recorded: voice memo
MyPhone is playingPierwsze dwa wiersze pokazują użycie urządzenia za pośrednictwem pojedynczych interfejsów (Player i Recorder). Ostatnie dwa wiersze pokazują użycie go za pośrednictwem złożonego interfejsu MediaDevice, który wymaga obu możliwości. Zwróć uwagę, że Twoja pojedyncza struktura SmartDevice spełnia wymagania wszystkich trzech interfejsów, ponieważ ma obie wymagane metody.
Spróbuj swoich sił
package main
import (
"bufio"
"fmt"
"os"
)
// TODO: Zaimplementuj UsePlayer, która przyjmuje Player i wywołuje jego metodę Play
// Powinna wypisać wynik Play()
// TODO: Zaimplementuj UseRecorder, która przyjmuje Recorder i ciąg znaków content
// Powinna wypisać wynik Record(content)
// TODO: Zaimplementuj UseMediaDevice, która przyjmuje MediaDevice i ciąg znaków content
// Powinna wypisać wynik Record(content), a następnie Play()
func main() {
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
deviceName := scanner.Text()
scanner.Scan()
content := scanner.Text()
// TODO: Utwórz SmartDevice o podanej nazwie
// TODO: Użyj urządzenia przez interfejs Player
// TODO: Użyj urządzenia przez interfejs Recorder
// TODO: Użyj urządzenia przez interfejs MediaDevice
_ = deviceName
_ = content
fmt.Println("Implement the solution")
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy OOP w Go
Pliki zewnętrzneObszar roboczy i moduły GoPakiety i importyNazwy eksportowane i nieeksportowaneWprowadzenie do OOP w GoStruktury jako klasyDefiniowanie metod dla strukturOdbiorniki wskaźnikowe i wartościoweInicjalizacja strukturFunkcje konstruktoraPodsumowanie – prosty kalkulator4Interfejsy
Wprowadzenie do interfejsówImplementacja niejawnaInterfejs jako kontraktPusty interfejs (any)Asercja typuPrzełącznik typówKompozycja interfejsówInterfejsy Stringer i ErrorPowtórka — kalkulator figur7Hermetyzacja
Pola eksportowane i nieeksportowaneHermetyzacja na poziomie pakietuMetody pobierające i ustawiająceUkrywanie informacji w GoPowtórka – dane studentów10Typy generyczne (Go 1.18+)
Wprowadzenie do typów generycznychParametry typówOgraniczenia typówStruktury generyczneObejście ograniczeń metod generycznychPodsumowanie — generyczna kolekcja2Typy i struktury w praktyce
Typy proste i złożoneDefiniowanie własnych typówTagi pól strukturStruktury anonimoweStruktury zagnieżdżoneWartości zerowe i domyślnePodsumowanie – książka kontaktów5Kompozycja zamiast dziedziczenia
Dlaczego Go nie ma dziedziczeniaPodstawy osadzania strukturPromowanie metodOsadzanie wielu strukturOsadzanie a agregacjaPrzesłanianie osadzonych metodPodsumowanie — hierarchia pracowników8Obsługa błędów i programowanie obiektowe
Interfejs błęduWłasne typy błędówOpakowywanie błędów (fmt.Errorf)Błędy wartowniczeerrors.Is() i errors.As()Panic, Defer i RecoverPodsumowanie — parser plików3Wskaźniki i pamięć
Podstawy wskaźników w GoWskaźniki do strukturPrzekazywanie przez wartość a przez referencjęFunkcja new()Odśmiecanie pamięci w GoPowtórka — kreator listy wiązanej6Polimorfizm w Go
Polimorfizm za pomocą interfejsówDuck typing w GoZasady spełniania interfejsówKolekcje polimorficzneWstrzykiwanie zależnościPowtórka — procesor płatności9Współbieżność i OOP
Podstawy goroutinesKanały i komunikacjaKanały buforowane i niebuforowaneInstrukcja selectsync.Mutex i sync.RWMutexsync.WaitGroupProjektowanie struktur bezpiecznych wątkowoPowtórka – pula workerów12Zaawansowane zagadnienia programowania obiektowego
Wzorzec opcji funkcyjnychWzorzec Builder w GoŁańcuchowe wywoływanie metodAliasy typów a definicje typówPodstawy refleksjiPrzegląd generowania koduPoćwicz samodzielnie: Kompilator Go online