Wzorzec adaptera
Część sekcji Programowanie obiektowe ścieżki C# w Coddy. Lekcja 57 z 70.
Wzorzec Adapter to wzorzec strukturalny, który umożliwia współpracę niezgodnych interfejsów. Działa jak most między dwiema klasami, przekształcając interfejs jednej klasy w interfejs oczekiwany przez klientów. Możesz myśleć o nim jak o adapterze zasilania, który pozwala podłączyć europejskie urządzenie do amerykańskiego gniazdka.
Ten wzorzec jest szczególnie przydatny, gdy chcesz użyć istniejącej klasy, ale jej interfejs nie pasuje do potrzeb Twojego kodu. Zamiast modyfikować oryginalną klasę (nad którą możesz nie mieć kontroli), tworzysz adapter, który ją opakowuje:
// Istniejąca klasa z niekompatybilnym interfejsem
public class OldPrinter
{
public void PrintMessage(string msg) => Console.WriteLine($"Old: {msg}");
}
// Interfejs, którego oczekuje twój kod
public interface IPrinter
{
void Print(string text);
}
// Adapter łączy niekompatybilne interfejsy
public class PrinterAdapter : IPrinter
{
private OldPrinter _oldPrinter;
public PrinterAdapter(OldPrinter oldPrinter)
{
_oldPrinter = oldPrinter;
}
public void Print(string text)
{
_oldPrinter.PrintMessage(text); // Deleguje wywołanie do starego interfejsu
}
}Teraz Twój kod może współpracować ze starą drukarką za pośrednictwem oczekiwanego interfejsu:
OldPrinter legacy = new OldPrinter();
IPrinter printer = new PrinterAdapter(legacy);
printer.Print("Hello"); // Old: HelloWzorzec Adapter jest nieoceniony podczas integrowania bibliotek innych firm lub starszego kodu z aplikacją. Kod klienta współpracuje z interfejsem IPrinter, nie zdając sobie sprawy, że za kulisami całą pracę wykonuje stara, niekompatybilna klasa.
Wyzwanie
ŁatwyZbudujmy system odtwarzacza multimediów z użyciem wzorca Adapter. Masz istniejącą bibliotekę audio, która odtwarza pliki MP3, ale Twoja aplikacja potrzebuje ujednoliconego interfejsu, który obsługuje różne typy multimediów. Utworzysz adapter, który wypełni tę lukę, umożliwiając nowoczesnemu odtwarzaczowi multimediów bezproblemową współpracę ze starszą biblioteką audio.
Rozmieścisz kod w trzech plikach:
LegacyAudio.cs: Reprezentuje istniejącą bibliotekę, której nie możesz modyfikować. Utwórz klasęLegacyAudioPlayerw przestrzeni nazwMediaSystem, z metodąPlayMp3(string filename), która zwraca ciąg znaków"Playing MP3: {filename}". To Twój „adaptowany obiekt” — klasa z niezgodnym interfejsem.MediaAdapter.cs: Utwórz interfejs i adapter w tej samej przestrzeni nazw. Zdefiniuj interfejsIMediaPlayerz metodąPlay(string filename), która zwraca ciąg znaków. Następnie utwórz klasęMediaPlayerAdapter, która implementujeIMediaPlayer. Adapter powinien opakowywać instancjęLegacyAudioPlayer(przekazaną przez konstruktor) i przekierowywać wywołaniePlaydo metodyPlayMp3starszego odtwarzacza.Program.cs: Połącz wszystko, tworząc starszy odtwarzacz, opakowując go w adapter i korzystając z adaptera za pośrednictwem interfejsuIMediaPlayer. To pokazuje, jak kod klienta może korzystać z nowoczesnego interfejsu, podczas gdy adapter w tle obsługuje komunikację ze starszym systemem.
Otrzymasz jedno wejście:
- Nazwę pliku do odtworzenia (np.
song.mp3)
Utwórz obiekt LegacyAudioPlayer, opakuj go w MediaPlayerAdapter, a następnie wywołaj Play na adapterze za pośrednictwem interfejsu IMediaPlayer i wypisz wynik.
Na przykład, jeśli wejściem jest favorite_track.mp3, wynikiem powinno być:
Playing MP3: favorite_track.mp3Piękno tego wzorca polega na tym, że główny kod korzysta wyłącznie z IMediaPlayer — nie wie, że faktyczną pracę wykonuje starsza biblioteka audio. Jeśli później zechcesz obsłużyć inną starszą bibliotekę, wystarczy utworzyć nowy adapter, nie zmieniając żadnego kodu klienta!
Spróbuj swoich sił
using System;
using MediaSystem;
class Program
{
public static void Main(string[] args)
{
// Odczytaj wprowadzoną nazwę pliku
string filename = Console.ReadLine();
// TODO: Utwórz instancję LegacyAudioPlayer
// TODO: Umieść ją w MediaPlayerAdapter
// TODO: Użyj adaptera przez interfejs IMediaPlayer
// i wypisz wynik wywołania Play z nazwą pliku
}
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrznePrzestrzenie nazw i dyrektywyWprowadzenie do klas i obiektówSłowo kluczowe „this”Metody i parametryPola a właściwościKonstruktoryInicjalizatory obiektówPodsumowanie — prosty kalkulator4Dziedziczenie
Podstawowa składnia dziedziczenia (:)Słowo kluczowe 'base'Słowa kluczowe virtual i overrideKlasy sealedBazowa klasa 'object'Powtórzenie – hierarchia pracowników7Zaawansowane funkcje
Przeciążanie operatorówIndeksery (this[])Nadpisywanie ToString()Metody rozszerzającePodsumowanie – własna lista2Właściwości i składowe statyczne
Właściwości automatyczneWłaściwości tylko do odczytu i zapisuPola i metody statyczneKlasy statyczneSkładowe z ciałem wyrażeniowym5Polimorfizm i interfejsy
Polimorfizm czasu kompilacji a czasu wykonaniaInterfejs a klasa abstrakcyjnaWiele interfejsówJawne implementowanie interfejsówRzutowanie w górę i w dółPowtórka — kalkulator kształtów8Zaawansowane koncepcje OOP
Kompozycja zamiast dziedziczeniaTypy generyczne (klasy i metody)Delegaty i zdarzeniaAtrybuty i refleksjaIDisposable i instrukcja usingPodstawy wstrzykiwania zależności11Wzorce projektowe, część 2
Wzorzec poleceniaWzorzec adapteraWzorzec dekoratoraWzorzec metody szablonowejWzorzec stanuWzorzec kompozytu3Architektura klas
Dane instancji a dane statyczneSłowa kluczowe 'readonly' i 'const'Pola zapasowePowtórzenie — menedżer kont bankowych6Hermetyzacja
Modyfikatory dostępuWłaściwości w hermetyzacjiImplementacja ukrywania danychWzorce niezmiennościPowtórka — dane studentów9Argumenty zmiennej liczby
Słowo kluczowe „params”Parametry opcjonalneArgumenty nazwanePrzeciążanie metodPoćwicz samodzielnie: Kompilator C# online