Wzorzec adaptera
Część sekcji Programowanie obiektowe ścieżki Dart w Coddy. Lekcja 95 z 110.
Wzorzec Adapter pozwala współpracować niezgodnym interfejsom. Działa jak most między dwiema klasami, które w innym przypadku nie mogłyby ze sobą współpracować, opakowując istniejącą klasę w nowy interfejs oczekiwany przez klientów. Jest to szczególnie przydatne podczas integrowania bibliotek innych firm lub starszego kodu z aplikacją.
Wyobraź sobie, że masz system, który pracuje z danymi JSON, ale musisz zintegrować komponent, który generuje wyłącznie XML. Zamiast modyfikować którąkolwiek z klas, tworzysz adapter, który tłumaczy między nimi:
// Istniejący interfejs, którego oczekuje twój system
abstract class JsonData {
String getJson();
}
// Starsza klasa z niekompatybilnym interfejsem
class XmlService {
String getXml() {
return '<data><name>John</name></data>';
}
}
// Adapter zapewnia zgodność XmlService z JsonData
class XmlToJsonAdapter implements JsonData {
final XmlService _xmlService;
XmlToJsonAdapter(this._xmlService);
@override
String getJson() {
String xml = _xmlService.getXml();
// Konwertuj XML na JSON (uproszczone)
return '{"name": "John"}';
}
}
void main() {
var xmlService = XmlService();
var adapter = XmlToJsonAdapter(xmlService);
print(adapter.getJson()); // {"name": "John"}
}XmlToJsonAdapter opakowuje XmlService i implementuje interfejs JsonData. Kod klienta korzysta ze znanego interfejsu JsonData, nie wiedząc, że dane pierwotnie pochodziły ze źródła XML. Adapter obsługuje całe tłumaczenie wewnętrznie.
Użyj wzorca Adapter, gdy chcesz użyć istniejącej klasy, ale jej interfejs nie odpowiada temu, czego potrzebujesz, lub gdy chcesz utworzyć klasę wielokrotnego użytku, która współpracuje z klasami mającymi niekompatybilne interfejsy.
Wyzwanie
ŁatwyZbudujmy system adaptera odtwarzacza multimediów! Wyobraź sobie, że masz nowoczesny system audio, który oczekuje, że wszystkie źródła multimediów będą dostarczać dźwięk za pośrednictwem standardowego interfejsu, ale musisz zintegrować staromodny gramofon, który wytwarza dźwięk w zupełnie inny sposób.
Utworzysz dwa pliki, aby uporządkować implementację wzorca adaptera:
media_adapter.dart: Ten plik zawiera interfejs i klasy adaptera. Zdefiniuj klasę abstrakcyjnąAudioSource, której oczekuje Twój nowoczesny system — powinna mieć metodęString playAudio(), która zwraca wyjście audio jako ciąg znaków. Następnie utwórz klasęVinylPlayerreprezentującą starszy sprzęt — ma poletrackNameoraz metodęString spinRecord(), która zwraca*crackle* Playing vinyl: [trackName] *crackle*. Na koniec zbudujVinylAdapter, który implementujeAudioSourcei opakowujeVinylPlayer. MetodaplayAudio()adaptera powinna wywoływać metodęspinRecord()odtwarzacza winylowego i zwracać wynik — w ten sposób łączy niezgodne interfejsy.main.dart: Zaimportuj plik adaptera multimediów i pokaż, jak adapter pozwala używać starego odtwarzacza winylowego w kodzie, który oczekuje nowoczesnego interfejsuAudioSource. UtwórzVinylPlayerz nazwą utworuBohemian Rhapsody. Następnie utwórzVinylAdapter, który opakowuje ten odtwarzacz winylowy. Przypisz adapter do zmiennej typuAudioSource, aby wykazać, że jest zgodny z oczekiwanym interfejsem. WywołajplayAudio()na źródle audio i wyświetl wynik.
Piękno tego wzorca polega na tym, że Twój główny kod korzysta ze standardowego interfejsu AudioSource — nie musi wiedzieć, że za kulisami faktyczną pracę wykonuje stary odtwarzacz winylowy!
Oczekiwany wynik:
*crackle* Playing vinyl: Bohemian Rhapsody *crackle*Spróbuj swoich sił
import 'media_adapter.dart';
void main() {
// TODO: Utwórz VinylPlayer z nazwą utworu "Bohemian Rhapsody"
// TODO: Utwórz VinylAdapter, który opakowuje odtwarzacz winylowy
// TODO: Zapisz adapter w zmiennej typu AudioSource
// TODO: Wywołaj playAudio() na swoim źródle dźwięku i wyświetl wynik
}
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
Pliki zewnętrzneBiblioteki i importyWprowadzenie do OOPKlasy a obiektySłowo kluczowe thisMetodyZmienne instancjiPodstawy konstruktorówPowtórka – prosty kalkulator4Bezpieczeństwo wartości null
Wprowadzenie do bezpieczeństwa wartości nullTypy dopuszczające null i niedopuszczające nullOperatory ? i !Słowo kluczowe late a bezpieczeństwo wartości nullOperatory uwzględniające nullBezpieczeństwo wartości null w klasachPodsumowanie — system profili użytkowników7Klasy abstrakcyjne i interfejsy
Klasy abstrakcyjneMetody abstrakcyjneInterfejsy w DartInterfejsy niejawneImplementowanie a rozszerzanieWiele interfejsówPowtórka — kalkulator kształtów10Kolekcje i typy generyczne
Przegląd List, Set i MapKolekcje bezpieczne typowoKlasy generyczneMetody generyczneOgraniczenia typów generycznychIterable i IteratorPowtórka — generyczne przechowywanie danych13Zaawansowane koncepcje OOP
Kompozycja a dziedziczenieMetody rozszerzająceKlasy wywoływalneKlasy zapieczętowane (Dart 3)Rekordy (Dart 3)Wzorce i dopasowywanie (3.0)Typy wyliczeniowe z metodami16Projekt: Zarządzanie biblioteką
Omówienie projektuKlasy książek i użytkowników2Konstruktory w Dart
Konstruktor domyślnyKonstruktory nazwaneListy inicjalizująceKonstruktory stałeKonstruktory fabryczneKonstruktory przekierowującePodsumowanie — budowanie kształtów5Hermetyzacja
Elementy publiczne a prywatneKonwencja prefiksu _Prywatność na poziomie bibliotekiGettery i settery — szczegółowoUkrywanie informacjiPodsumowanie — dane uczniów8Domieszki
Wprowadzenie do domieszekTworzenie domieszekKorzystanie z wielu domieszekSłowo kluczowe on w domieszkachDomieszka a dziedziczenieDomieszka a interfejsPodsumowanie – system zwierząt11Metody specjalne
Nadpisanie toString()Nadpisanie hashCode i ==Interfejs ComparableMetoda call()Nadpisanie noSuchMethodPodsumowanie — własna kolekcja14Wzorce projektowe, część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec ObserverWzorzec Strategy3Właściwości klas
Elementy instancji a elementy statycznePola final i constZmienne inicjalizowane z opóźnieniemMetody i pola statyczneGettery i setteryPowtórzenie – menedżer kont bankowych6Dziedziczenie
Podstawy dziedziczeniaSłowo kluczowe superPrzesłanianie metodAdnotacja @overrideSłowo kluczowe final dla klasKonstruktory i dziedziczeniePowtórzenie – hierarchia pracowników9Polimorfizm
Podstawy polimorfizmuPolimorfizm za pomocą interfejsówSprawdzanie typu w czasie działaniaOperatory is i asSłowo kluczowe covariantPodsumowanie — procesor płatności12Asynchroniczne OOP
Futures i async/awaitPodstawy strumieniKontrolery strumieniKonstruktory asynchroniczneAsynchroniczność w metodach klasyPodsumowanie — pobieranie danych15Wzorce projektowe, część 2
Wzorzec poleceniaWzorzec adapteraWzorzec dekoratoraWzorzec metody szablonowejWzorzec stanuWzorzec kompozytuWzorzec repozytoriumPoćwicz samodzielnie: Kompilator Dart online